Organize workspace: Frontend, Backend, and Tests in one repo
This commit is contained in:
11
.vscode-server/data/User/History/-23e511c6/3Okw.ts
Normal file
11
.vscode-server/data/User/History/-23e511c6/3Okw.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// vitest.config.ts
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
},
|
||||
})
|
||||
1
.vscode-server/data/User/History/-23e511c6/entries.json
Normal file
1
.vscode-server/data/User/History/-23e511c6/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/vitest.config.ts","entries":[{"id":"3Okw.ts","timestamp":1772653272270},{"id":"hUJW.ts","timestamp":1772654078047}]}
|
||||
16
.vscode-server/data/User/History/-23e511c6/hUJW.ts
Normal file
16
.vscode-server/data/User/History/-23e511c6/hUJW.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// vitest.config.ts
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
server: {
|
||||
deps: {
|
||||
inline: [/@exodus\/bytes/, /html-encoding-sniffer/],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
32
.vscode-server/data/User/History/-466923f8/Z7Qa.json
Normal file
32
.vscode-server/data/User/History/-466923f8/Z7Qa.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Seasoned",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare",
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/generative-ai": "^0.24.1",
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@prisma/client": "^7.4.2",
|
||||
"dotenv": "^17.3.1",
|
||||
"nuxt": "^4.1.3",
|
||||
"prisma": "^6.19.2",
|
||||
"sass": "^1.97.3",
|
||||
"vue": "^3.5.29",
|
||||
"vue-router": "^4.6.4",
|
||||
"vuetify": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.3.3",
|
||||
"@vitejs/plugin-vue": "^6.0.4",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"jsdom": "^28.1.0",
|
||||
"vitest": "^4.0.18"
|
||||
}
|
||||
}
|
||||
1
.vscode-server/data/User/History/-466923f8/entries.json
Normal file
1
.vscode-server/data/User/History/-466923f8/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/package.json","entries":[{"id":"Z7Qa.json","timestamp":1772653302431}]}
|
||||
26
.vscode-server/data/User/History/-4a34cfdd/dvL4.json
Normal file
26
.vscode-server/data/User/History/-4a34cfdd/dvL4.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"[python]": {
|
||||
"editor.formatOnType": true
|
||||
},
|
||||
"security.workspace.trust.untrustedFiles": "open",
|
||||
"editor.minimap.enabled": false,
|
||||
"editor.unicodeHighlight.invisibleCharacters": false,
|
||||
"redhat.telemetry.enabled": false,
|
||||
"window.zoomLevel": 1,
|
||||
"editor.unicodeHighlight.nonBasicASCII": false,
|
||||
"remote.SSH.remotePlatform": {
|
||||
"neptune.wrigglyt.xyz": "linux",
|
||||
"10.0.11.3": "linux"
|
||||
},
|
||||
"jupyter.askForKernelRestart": false,
|
||||
"git.openRepositoryInParentFolders": "never",
|
||||
"workbench.colorTheme": "Shades of Purple (Super Dark)",
|
||||
"jdk.telemetry.enabled": false,
|
||||
"git.autofetch": true,
|
||||
"cSpell.userWords": [
|
||||
"Tutankhamun",
|
||||
"vuetify",
|
||||
"wordle",
|
||||
"wordlist"
|
||||
]
|
||||
}
|
||||
1
.vscode-server/data/User/History/-4a34cfdd/entries.json
Normal file
1
.vscode-server/data/User/History/-4a34cfdd/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-userdata:/c%3A/Users/Chloe/AppData/Roaming/Code/User/settings.json","entries":[{"id":"dvL4.json","timestamp":1772650572407}]}
|
||||
110
.vscode-server/data/User/History/-4dbca32d/4Y2E.vue
Normal file
110
.vscode-server/data/User/History/-4dbca32d/4Y2E.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-main>
|
||||
<v-container>
|
||||
<v-card class="pa-5 mx-auto mt-10" max-width="500" elevation="10">
|
||||
<v-card-title class="text-center">Seasoned AI</v-card-title>
|
||||
|
||||
<v-divider class="my-3"></v-divider>
|
||||
|
||||
<v-file-input
|
||||
v-model="files"
|
||||
label="Pick a recipe photo"
|
||||
prepend-icon="mdi-camera"
|
||||
variant="outlined"
|
||||
accept="image/*"
|
||||
></v-file-input>
|
||||
|
||||
<v-btn
|
||||
color="primary"
|
||||
block
|
||||
size="x-large"
|
||||
:loading="loading"
|
||||
@click="uploadImage"
|
||||
>
|
||||
Analyze Recipe
|
||||
</v-btn>
|
||||
|
||||
<div v-if="recipe" class="mt-5">
|
||||
<h2 class="text-h4 mb-4">{{ recipe.title }}</h2>
|
||||
<p class="text-subtitle-1 mb-6 text-grey-darken-1">{{ recipe.description }}</p>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" md="5">
|
||||
<h3 class="text-h6 mb-2">Ingredients</h3>
|
||||
<v-list lines="one" variant="flat" class="bg-grey-lighten-4 rounded-lg">
|
||||
<v-list-item v-for="(item, i) in recipe.ingredients" :key="i">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-circle-small"></v-icon>
|
||||
</template>
|
||||
{{ item }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="7">
|
||||
<h3 class="text-h6 mb-2">Instructions</h3>
|
||||
<v-timeline side="end" align="start" density="compact">
|
||||
<v-timeline-item
|
||||
v-for="(step, i) in recipe.instructions"
|
||||
:key="i"
|
||||
dot-color="primary"
|
||||
size="x-small"
|
||||
>
|
||||
<div class="text-body-1">{{ step }}</div>
|
||||
</v-timeline-item>
|
||||
</v-timeline>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import axios from 'axios'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const files = ref([])
|
||||
const loading = ref(false)
|
||||
const recipe = ref(null)
|
||||
|
||||
const uploadImage = async () => {
|
||||
// 1. Debug: Check what Vuetify is actually giving us
|
||||
console.log("Files variable:", files.value);
|
||||
|
||||
// Vuetify 3 v-file-input can return a single File or an Array of Files
|
||||
// We need to ensure we have the actual File object
|
||||
const fileToUpload = Array.isArray(files.value) ? files.value[0] : files.value;
|
||||
|
||||
if (!fileToUpload) {
|
||||
alert("Please select a file first!");
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
const formData = new FormData();
|
||||
|
||||
// 2. Append the file. The string 'image' MUST match your C# parameter name
|
||||
formData.append('image', fileToUpload);
|
||||
|
||||
try {
|
||||
// 3. Post with explicit multipart/form-data header (Axios usually does this, but let's be sure)
|
||||
const response = await axios.post('http://localhost:5000/api/recipe/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
|
||||
recipe.value = response.data;
|
||||
console.log("Success:", response.data);
|
||||
} catch (error) {
|
||||
console.error("Detailed Error:", error.response?.data || error.message);
|
||||
alert("Backend error: Check the browser console for details.");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
67
.vscode-server/data/User/History/-4dbca32d/KNJK.vue
Normal file
67
.vscode-server/data/User/History/-4dbca32d/KNJK.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-app-bar title="Seasoned AI Recipe Parser" color="primary"></v-app-bar>
|
||||
<v-main>
|
||||
<v-container>
|
||||
<v-card class="mx-auto mt-5" max-width="600">
|
||||
<v-card-text>
|
||||
<v-file-input
|
||||
v-model="selectedFile"
|
||||
label="Upload Recipe Photo"
|
||||
accept="image/*"
|
||||
prepend-icon="mdi-camera"
|
||||
@change="onFileSelect"
|
||||
></v-file-input>
|
||||
|
||||
<v-btn
|
||||
:loading="loading"
|
||||
color="success"
|
||||
block
|
||||
@click="uploadImage"
|
||||
:disabled="!selectedFile"
|
||||
>
|
||||
Analyze with C# Backend
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card v-if="recipe" class="mx-auto mt-5" max-width="600">
|
||||
<v-card-title>{{ recipe.title }}</v-card-title>
|
||||
<v-card-text>
|
||||
<div class="text-subtitle-1">Ingredients:</div>
|
||||
<ul>
|
||||
<li v-for="item in recipe.ingredients" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import axios from 'axios'
|
||||
const selectedFile = ref(null)
|
||||
const loading = ref(false)
|
||||
const recipe = ref(null)
|
||||
|
||||
const uploadImage = async () => {
|
||||
if (!selectedFile.value) return
|
||||
loading.value = true
|
||||
|
||||
const formData = new FormData()
|
||||
// We use [0] because v-file-input returns an array
|
||||
formData.append('image', selectedFile.value[0])
|
||||
|
||||
try {
|
||||
// This points to your C# Backend we built earlier!
|
||||
const response = await axios.post('http://localhost:5000/api/recipe/upload', formData)
|
||||
recipe.value = response.data
|
||||
} catch (error) {
|
||||
console.error("Backend Error:", error)
|
||||
alert("Make sure your C# Backend is running on port 5000!")
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
1
.vscode-server/data/User/History/-4dbca32d/entries.json
Normal file
1
.vscode-server/data/User/History/-4dbca32d/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/app/app.vue","entries":[{"id":"KNJK.vue","timestamp":1772654853257},{"id":"yQXD.vue","timestamp":1772655854730},{"id":"wG0o.vue","timestamp":1772658220344},{"id":"4Y2E.vue","timestamp":1772660655062}]}
|
||||
82
.vscode-server/data/User/History/-4dbca32d/wG0o.vue
Normal file
82
.vscode-server/data/User/History/-4dbca32d/wG0o.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-main>
|
||||
<v-container>
|
||||
<v-card class="pa-5 mx-auto mt-10" max-width="500" elevation="10">
|
||||
<v-card-title class="text-center">Seasoned AI</v-card-title>
|
||||
|
||||
<v-divider class="my-3"></v-divider>
|
||||
|
||||
<v-file-input
|
||||
v-model="files"
|
||||
label="Pick a recipe photo"
|
||||
prepend-icon="mdi-camera"
|
||||
variant="outlined"
|
||||
accept="image/*"
|
||||
></v-file-input>
|
||||
|
||||
<v-btn
|
||||
color="primary"
|
||||
block
|
||||
size="x-large"
|
||||
:loading="loading"
|
||||
@click="uploadImage"
|
||||
>
|
||||
Analyze Recipe
|
||||
</v-btn>
|
||||
|
||||
<div v-if="recipe" class="mt-5">
|
||||
<h3 class="text-h6">{{ recipe.title }}</h3>
|
||||
<p>{{ recipe.description }}</p>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import axios from 'axios'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const files = ref([])
|
||||
const loading = ref(false)
|
||||
const recipe = ref(null)
|
||||
|
||||
const uploadImage = async () => {
|
||||
// 1. Debug: Check what Vuetify is actually giving us
|
||||
console.log("Files variable:", files.value);
|
||||
|
||||
// Vuetify 3 v-file-input can return a single File or an Array of Files
|
||||
// We need to ensure we have the actual File object
|
||||
const fileToUpload = Array.isArray(files.value) ? files.value[0] : files.value;
|
||||
|
||||
if (!fileToUpload) {
|
||||
alert("Please select a file first!");
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
const formData = new FormData();
|
||||
|
||||
// 2. Append the file. The string 'image' MUST match your C# parameter name
|
||||
formData.append('image', fileToUpload);
|
||||
|
||||
try {
|
||||
// 3. Post with explicit multipart/form-data header (Axios usually does this, but let's be sure)
|
||||
const response = await axios.post('http://localhost:5000/api/recipe/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
|
||||
recipe.value = response.data;
|
||||
console.log("Success:", response.data);
|
||||
} catch (error) {
|
||||
console.error("Detailed Error:", error.response?.data || error.message);
|
||||
alert("Backend error: Check the browser console for details.");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
68
.vscode-server/data/User/History/-4dbca32d/yQXD.vue
Normal file
68
.vscode-server/data/User/History/-4dbca32d/yQXD.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-main>
|
||||
<v-container>
|
||||
<v-card class="pa-5 mx-auto mt-10" max-width="500" elevation="10">
|
||||
<v-card-title class="text-center">Seasoned AI</v-card-title>
|
||||
|
||||
<v-divider class="my-3"></v-divider>
|
||||
|
||||
<v-file-input
|
||||
v-model="files"
|
||||
label="Pick a recipe photo"
|
||||
prepend-icon="mdi-camera"
|
||||
variant="outlined"
|
||||
accept="image/*"
|
||||
></v-file-input>
|
||||
|
||||
<v-btn
|
||||
color="primary"
|
||||
block
|
||||
size="x-large"
|
||||
:loading="loading"
|
||||
@click="uploadImage"
|
||||
>
|
||||
Analyze Recipe
|
||||
</v-btn>
|
||||
|
||||
<div v-if="recipe" class="mt-5">
|
||||
<h3 class="text-h6">{{ recipe.title }}</h3>
|
||||
<p>{{ recipe.description }}</p>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import axios from 'axios'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const files = ref([])
|
||||
const loading = ref(false)
|
||||
const recipe = ref(null)
|
||||
|
||||
const uploadImage = async () => {
|
||||
if (!files.value || files.value.length === 0) {
|
||||
alert("Please select a file first!")
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
const formData = new FormData()
|
||||
// Vuetify v-file-input returns an array
|
||||
formData.append('image', files.value[0])
|
||||
|
||||
try {
|
||||
const response = await axios.post('http://localhost:5000/api/recipe/upload', formData)
|
||||
recipe.value = response.data
|
||||
console.log("Success:", response.data)
|
||||
} catch (error) {
|
||||
console.error("Connection Error:", error)
|
||||
alert("Could not connect to C# Backend on port 5000")
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
38
.vscode-server/data/User/History/-4f4fc408/4vNe.ts
Normal file
38
.vscode-server/data/User/History/-4f4fc408/4vNe.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
|
||||
devtools: { enabled: true },
|
||||
|
||||
future: {
|
||||
compatibilityVersion: 4,
|
||||
},
|
||||
|
||||
srcDir: 'app/',
|
||||
|
||||
css: [
|
||||
'vuetify/lib/styles/main.sass',
|
||||
'@mdi/font/css/materialdesignicons.min.css',
|
||||
],
|
||||
|
||||
build: {
|
||||
transpile: ['vuetify'],
|
||||
},
|
||||
|
||||
modules: [
|
||||
'vuetify-nuxt-module'
|
||||
],
|
||||
|
||||
runtimeConfig: {
|
||||
geminiApiKey: '',
|
||||
},
|
||||
|
||||
vite: {
|
||||
server: {
|
||||
hmr: {
|
||||
protocol: 'ws',
|
||||
host: 'localhost',
|
||||
port: 3000
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
25
.vscode-server/data/User/History/-4f4fc408/YA3U.ts
Normal file
25
.vscode-server/data/User/History/-4f4fc408/YA3U.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
devtools: { enabled: true },
|
||||
future: {
|
||||
compatibilityVersion: 4,
|
||||
},
|
||||
srcDir: 'app/',
|
||||
css: [
|
||||
'vuetify/lib/styles/main.sass',
|
||||
'@mdi/font/css/materialdesignicons.min.css',
|
||||
],
|
||||
build: {
|
||||
transpile: ['vuetify'],
|
||||
},
|
||||
|
||||
modules: [
|
||||
'vuetify-nuxt-module'
|
||||
],
|
||||
|
||||
// Environment Variables for Gemini
|
||||
runtimeConfig: {
|
||||
geminiApiKey: '',
|
||||
},
|
||||
})
|
||||
1
.vscode-server/data/User/History/-4f4fc408/entries.json
Normal file
1
.vscode-server/data/User/History/-4f4fc408/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/nuxt.config.ts","entries":[{"id":"YA3U.ts","timestamp":1772656098549},{"id":"4vNe.ts","timestamp":1772656590628}]}
|
||||
27
.vscode-server/data/User/History/-6061d294/DOP7.cs
Normal file
27
.vscode-server/data/User/History/-6061d294/DOP7.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Seasoned.Backend.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddScoped<IRecipeService, RecipeService>();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddDefaultPolicy(policy =>
|
||||
{
|
||||
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
app.UseCors();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
29
.vscode-server/data/User/History/-6061d294/H1dq.cs
Normal file
29
.vscode-server/data/User/History/-6061d294/H1dq.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Seasoned.Backend.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddScoped<IRecipeService, RecipeService>();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowAll", policy =>
|
||||
{
|
||||
policy.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader();
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
app.UseCors("AllowAll");
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
1
.vscode-server/data/User/History/-6061d294/entries.json
Normal file
1
.vscode-server/data/User/History/-6061d294/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned.Backend/Program.cs","entries":[{"id":"f7pI.cs","timestamp":1772653808017},{"id":"uV5H.cs","timestamp":1772655393867},{"id":"DOP7.cs","timestamp":1772655404025},{"id":"H1dq.cs","timestamp":1772656795188}]}
|
||||
18
.vscode-server/data/User/History/-6061d294/f7pI.cs
Normal file
18
.vscode-server/data/User/History/-6061d294/f7pI.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Seasoned.Backend.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddScoped<IRecipeService, RecipeService>();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
26
.vscode-server/data/User/History/-6061d294/uV5H.cs
Normal file
26
.vscode-server/data/User/History/-6061d294/uV5H.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Seasoned.Backend.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddScoped<IRecipeService, RecipeService>();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddDefaultPolicy(policy =>
|
||||
{
|
||||
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
8
.vscode-server/data/User/History/-690ef53f/ZKMQ.cs
Normal file
8
.vscode-server/data/User/History/-690ef53f/ZKMQ.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public interface IRecipeService
|
||||
{
|
||||
Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image);
|
||||
}
|
||||
1
.vscode-server/data/User/History/-690ef53f/entries.json
Normal file
1
.vscode-server/data/User/History/-690ef53f/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned.Backend/Services/IRecipeService.cs","entries":[{"id":"ZKMQ.cs","timestamp":1772653775570}]}
|
||||
1
.vscode-server/data/User/History/-a412837/entries.json
Normal file
1
.vscode-server/data/User/History/-a412837/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/Seasoned.code-workspace","entries":[{"id":"zqpI.code-workspace","timestamp":1772653555260}]}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "../Seasoned.Backend"
|
||||
},
|
||||
{
|
||||
"path": "../Seasoned.Tests"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
6
.vscode-server/data/User/History/23b69877/90iu
Normal file
6
.vscode-server/data/User/History/23b69877/90iu
Normal file
@@ -0,0 +1,6 @@
|
||||
# 1. The "Key" to the AI (Gemini)
|
||||
GEMINI_API_KEY=AIzaSyCB_8aoRxQEXeO2cakFn_u5dttRbyThOf4
|
||||
|
||||
# 2. The "Address" to the Database (Postgres)
|
||||
# Replace 'localhost' with theserver IP when you deploy
|
||||
DATABASE_URL="postgresql://seasoned_admin:your_secure_password_here@localhost:5432/seasoned_db?schema=public"
|
||||
1
.vscode-server/data/User/History/23b69877/entries.json
Normal file
1
.vscode-server/data/User/History/23b69877/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/.env","entries":[{"id":"90iu","timestamp":1772655859776}]}
|
||||
1
.vscode-server/data/User/History/2b7be92a/entries.json
Normal file
1
.vscode-server/data/User/History/2b7be92a/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned.Backend/Controllers/RecipeController.cs","entries":[{"id":"vcso.cs","timestamp":1772653722495},{"id":"gfRM.cs","timestamp":1772658067690}]}
|
||||
30
.vscode-server/data/User/History/2b7be92a/gfRM.cs
Normal file
30
.vscode-server/data/User/History/2b7be92a/gfRM.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Seasoned.Backend.Services;
|
||||
using Seasoned.Backend.DTOs;
|
||||
|
||||
namespace Seasoned.Backend.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class RecipeController : ControllerBase
|
||||
{
|
||||
private readonly IRecipeService _recipeService;
|
||||
|
||||
// Dependency Injection: The service is "injected" here
|
||||
public RecipeController(IRecipeService recipeService)
|
||||
{
|
||||
_recipeService = recipeService;
|
||||
}
|
||||
|
||||
[HttpPost("upload")]
|
||||
public async Task<ActionResult<RecipeResponseDto>> UploadRecipe([FromForm] IFormFile image)
|
||||
{
|
||||
if (image == null || image.Length == 0)
|
||||
{
|
||||
return BadRequest("No image uploaded.");
|
||||
}
|
||||
|
||||
var result = await _recipeService.ParseRecipeImageAsync(image);
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
30
.vscode-server/data/User/History/2b7be92a/vcso.cs
Normal file
30
.vscode-server/data/User/History/2b7be92a/vcso.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Seasoned.Backend.Services;
|
||||
using Seasoned.Backend.DTOs;
|
||||
|
||||
namespace Seasoned.Backend.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class RecipeController : ControllerBase
|
||||
{
|
||||
private readonly IRecipeService _recipeService;
|
||||
|
||||
// Dependency Injection: The service is "injected" here
|
||||
public RecipeController(IRecipeService recipeService)
|
||||
{
|
||||
_recipeService = recipeService;
|
||||
}
|
||||
|
||||
[HttpPost("upload")]
|
||||
public async Task<ActionResult<RecipeResponseDto>> UploadRecipe(IFormFile image)
|
||||
{
|
||||
if (image == null || image.Length == 0)
|
||||
{
|
||||
return BadRequest("No image uploaded.");
|
||||
}
|
||||
|
||||
var result = await _recipeService.ParseRecipeImageAsync(image);
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
15
.vscode-server/data/User/History/38092a26/8Yqw.ts
Normal file
15
.vscode-server/data/User/History/38092a26/8Yqw.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createVuetify } from 'vuetify'
|
||||
import * as components from 'vuetify/components'
|
||||
import * as directives from 'vuetify/directives'
|
||||
// If you're using Nuxt 4, we use the standard 'nuxt/app' import to help the editor
|
||||
import { defineNuxtPlugin } from '#app'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const vuetify = createVuetify({
|
||||
ssr: true,
|
||||
components,
|
||||
directives,
|
||||
})
|
||||
|
||||
nuxtApp.vueApp.use(vuetify)
|
||||
})
|
||||
17
.vscode-server/data/User/History/38092a26/KNbC.ts
Normal file
17
.vscode-server/data/User/History/38092a26/KNbC.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createVuetify } from 'vuetify'
|
||||
import * as components from 'vuetify/components'
|
||||
import * as directives from 'vuetify/directives'
|
||||
|
||||
// We use the global defineNuxtPlugin.
|
||||
// If it's still red, it's just a VS Code cache issue—the code is valid.
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const vuetify = createVuetify({
|
||||
ssr: true,
|
||||
components,
|
||||
directives,
|
||||
})
|
||||
|
||||
// We cast nuxtApp as 'any' ONLY if the editor is being stubborn
|
||||
// during your setup, but npx nuxi prepare usually fixes the real type.
|
||||
nuxtApp.vueApp.use(vuetify)
|
||||
})
|
||||
14
.vscode-server/data/User/History/38092a26/R09H.ts
Normal file
14
.vscode-server/data/User/History/38092a26/R09H.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// plugins/vuetify.ts
|
||||
import { createVuetify } from 'vuetify'
|
||||
import * as components from 'vuetify/components'
|
||||
import * as directives from 'vuetify/directives'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const vuetify = createVuetify({
|
||||
ssr: true,
|
||||
components,
|
||||
directives,
|
||||
})
|
||||
|
||||
nuxtApp.vueApp.use(vuetify)
|
||||
})
|
||||
1
.vscode-server/data/User/History/38092a26/entries.json
Normal file
1
.vscode-server/data/User/History/38092a26/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/plugins/vuetify.ts","entries":[{"id":"R09H.ts","timestamp":1772654162226},{"id":"8Yqw.ts","timestamp":1772654356633},{"id":"KNbC.ts","timestamp":1772654431873},{"id":"z5oj.ts","timestamp":1772654663808}]}
|
||||
14
.vscode-server/data/User/History/38092a26/z5oj.ts
Normal file
14
.vscode-server/data/User/History/38092a26/z5oj.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// @ts-nocheck
|
||||
import { createVuetify } from 'vuetify'
|
||||
import * as components from 'vuetify/components'
|
||||
import * as directives from 'vuetify/directives'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const vuetify = createVuetify({
|
||||
ssr: true,
|
||||
components,
|
||||
directives,
|
||||
})
|
||||
|
||||
nuxtApp.vueApp.use(vuetify)
|
||||
})
|
||||
8
.vscode-server/data/User/History/502b6f20/4b9C.ts
Normal file
8
.vscode-server/data/User/History/502b6f20/4b9C.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
|
||||
describe('Frontend Setup', () => {
|
||||
it('checks that 1 + 1 is 2', () => {
|
||||
expect(1 + 1).toBe(2)
|
||||
})
|
||||
})
|
||||
1
.vscode-server/data/User/History/502b6f20/entries.json
Normal file
1
.vscode-server/data/User/History/502b6f20/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned/test/App.spec.ts","entries":[{"id":"4b9C.ts","timestamp":1772653995852}]}
|
||||
9
.vscode-server/data/User/History/5571ccf7/WSMI.cs
Normal file
9
.vscode-server/data/User/History/5571ccf7/WSMI.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Seasoned.Backend.DTOs;
|
||||
|
||||
public class RecipeResponseDto
|
||||
{
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public List<string> Ingredients { get; set; } = new();
|
||||
public List<string> Instructions { get; set; } = new();
|
||||
}
|
||||
1
.vscode-server/data/User/History/5571ccf7/entries.json
Normal file
1
.vscode-server/data/User/History/5571ccf7/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned.Backend/DTOs/RecipeResponseDto.cs","entries":[{"id":"WSMI.cs","timestamp":1772653671151}]}
|
||||
47
.vscode-server/data/User/History/76ebe8a8/FuxE.cs
Normal file
47
.vscode-server/data/User/History/76ebe8a8/FuxE.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Seasoned.Backend.Controllers;
|
||||
using Seasoned.Backend.Services;
|
||||
using Seasoned.Backend.DTOs;
|
||||
|
||||
namespace Seasoned.Tests;
|
||||
|
||||
public class RecipeControllerTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ParseRecipe_ReturnsOk_WhenImageIsValid()
|
||||
{
|
||||
// 1. Arrange: Create a "Fake" Service
|
||||
var mockService = new Mock<IRecipeService>();
|
||||
var fakeRecipe = new RecipeResponseDto { Title = "Test Recipe" };
|
||||
|
||||
mockService.Setup(s => s.ParseImageAsync(It.IsAny<IFormFile>()))
|
||||
.ReturnsAsync(fakeRecipe);
|
||||
|
||||
var controller = new RecipeController(mockService.Object);
|
||||
|
||||
// Create a fake image file
|
||||
var content = "fake image content";
|
||||
var fileName = "test.jpg";
|
||||
var ms = new MemoryStream();
|
||||
var writer = new StreamWriter(ms);
|
||||
writer.Write(content);
|
||||
writer.Flush();
|
||||
ms.Position = 0;
|
||||
var mockFile = new FormFile(ms, 0, ms.Length, "id_from_form", fileName);
|
||||
|
||||
// 2. Act: Call the Controller
|
||||
var result = await controller.ParseRecipe(mockFile);
|
||||
|
||||
// 3. Assert: Check the result
|
||||
var okResult = result as OkObjectResult;
|
||||
okResult.Should().NotBeNull();
|
||||
okResult!.StatusCode.Should().Be(200);
|
||||
|
||||
var returnedRecipe = okResult.Value as RecipeResponseDto;
|
||||
returnedRecipe!.Title.Should().Be("Test Recipe");
|
||||
}
|
||||
}
|
||||
1
.vscode-server/data/User/History/76ebe8a8/entries.json
Normal file
1
.vscode-server/data/User/History/76ebe8a8/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned.Tests/UnitTest1.cs","entries":[{"id":"FuxE.cs","timestamp":1772653857111}]}
|
||||
55
.vscode-server/data/User/History/b03096/26Rk.cs
Normal file
55
.vscode-server/data/User/History/b03096/26Rk.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// 1. Initialize Content with the Role in the constructor
|
||||
var content = new Content(Role.User);
|
||||
|
||||
// 2. Assign the parts using dynamic to bypass the IPart/Part conversion headache
|
||||
content.Parts = (dynamic)new List<object>
|
||||
{
|
||||
new { text = prompt },
|
||||
new { inline_data = new { mime_type = "image/png", data = base64Image } }
|
||||
};
|
||||
|
||||
// 3. Create the request
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
// 4. Call the model
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
49
.vscode-server/data/User/History/b03096/2oaa.cs
Normal file
49
.vscode-server/data/User/History/b03096/2oaa.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
var content = new Content(Role.User);
|
||||
|
||||
content.Parts = new List<IPart>
|
||||
{
|
||||
(IPart)new Part { Text = prompt },
|
||||
(IPart)new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
};
|
||||
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
48
.vscode-server/data/User/History/b03096/4GWQ.cs
Normal file
48
.vscode-server/data/User/History/b03096/4GWQ.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
var content = new Content(Role.User);
|
||||
|
||||
content.Parts = new List<IPart>
|
||||
{
|
||||
(IPart)new Part { Text = prompt },
|
||||
(IPart)new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
};
|
||||
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
18
.vscode-server/data/User/History/b03096/77Sz.cs
Normal file
18
.vscode-server/data/User/History/b03096/77Sz.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
// Placeholder logic to satisfy the return type
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Mock Recipe",
|
||||
Description = "This is a placeholder until Gemini is linked.",
|
||||
Ingredients = new List<string> { "Ingredient A", "Ingredient B" },
|
||||
Instructions = new List<string> { "Cook it", "Eat it" }
|
||||
};
|
||||
}
|
||||
}
|
||||
43
.vscode-server/data/User/History/b03096/BJsp.cs
Normal file
43
.vscode-server/data/User/History/b03096/BJsp.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
var request = new GenerateContentRequest(prompt);
|
||||
|
||||
await request.AddMedia(base64Image, "image/png");
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
50
.vscode-server/data/User/History/b03096/DZeF.cs
Normal file
50
.vscode-server/data/User/History/b03096/DZeF.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
var parts = new List<IPart>
|
||||
{
|
||||
new Part { Text = prompt },
|
||||
new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
};
|
||||
|
||||
var content = new Content(parts);
|
||||
content.Role = Role.User;
|
||||
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
49
.vscode-server/data/User/History/b03096/GoWQ.cs
Normal file
49
.vscode-server/data/User/History/b03096/GoWQ.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
var content = new Content(Role.User);
|
||||
|
||||
content.Parts = new List<IPart>
|
||||
{
|
||||
(IPart)new Part { Text = prompt },
|
||||
(IPart)new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
};
|
||||
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
52
.vscode-server/data/User/History/b03096/Goe4.cs
Normal file
52
.vscode-server/data/User/History/b03096/Goe4.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
// Use the explicit string for the model to bypass the "Model.Gemini25Flash" error
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
// Use a dynamic request structure which the library supports for newer models
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// This is a more robust way to send the request in the latest version
|
||||
var response = await model.GenerateContent(new()
|
||||
{
|
||||
Contents = new List<Content>
|
||||
{
|
||||
new Content
|
||||
{
|
||||
Parts = new List<Part>
|
||||
{
|
||||
new() { Text = prompt },
|
||||
new() { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
52
.vscode-server/data/User/History/b03096/Gr2p.cs
Normal file
52
.vscode-server/data/User/History/b03096/Gr2p.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// Use the constructor that the error message suggested: Content(string role)
|
||||
var content = new Content(Role.User);
|
||||
|
||||
// Add parts manually to avoid the IPart/Part conversion headache
|
||||
content.Parts = new List<Part>
|
||||
{
|
||||
new Part { Text = prompt },
|
||||
new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
};
|
||||
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
// Call the model with the explicit request
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
55
.vscode-server/data/User/History/b03096/J28Z.cs
Normal file
55
.vscode-server/data/User/History/b03096/J28Z.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new Mscc.GenerativeAI.GoogleAI(_apiKey);
|
||||
|
||||
// Explicitly calling Gemini 2.5 Flash
|
||||
var model = googleAI.GenerativeModel(Mscc.GenerativeAI.Model.Gemini25Flash);
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// Using full namespace paths for all request objects
|
||||
var request = new Mscc.GenerativeAI.GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Mscc.GenerativeAI.Content>
|
||||
{
|
||||
new Mscc.GenerativeAI.Content
|
||||
{
|
||||
Role = Mscc.GenerativeAI.Role.User,
|
||||
Parts = new List<Mscc.GenerativeAI.Part>
|
||||
{
|
||||
new Mscc.GenerativeAI.TextPart { Text = prompt },
|
||||
new Mscc.GenerativeAI.InlineDataPart { MimeType = "image/png", Data = base64Image }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Result",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
47
.vscode-server/data/User/History/b03096/MbC8.cs
Normal file
47
.vscode-server/data/User/History/b03096/MbC8.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
// Using the 2026 model string
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var imageBytes = ms.ToArray();
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// 1. New GenerateContentRequest automatically handles the text
|
||||
var request = new GenerateContentRequest(prompt);
|
||||
|
||||
// 2. AddMedia is now the standard for version 3.x+
|
||||
// This handles the binary-to-base64 conversion internally!
|
||||
request.AddMedia(imageBytes, "image/png");
|
||||
|
||||
// 3. Send the unified request
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
49
.vscode-server/data/User/History/b03096/Smgs.cs
Normal file
49
.vscode-server/data/User/History/b03096/Smgs.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
// 1. Better Prompt: Tell Gemini exactly what the JSON should look like
|
||||
var prompt = @"Extract the recipe from this image.
|
||||
Return a JSON object with exactly these fields:
|
||||
{
|
||||
""title"": ""string"",
|
||||
""description"": ""string"",
|
||||
""ingredients"": [""string""],
|
||||
""instructions"": [""string""]
|
||||
}";
|
||||
|
||||
// 2. Set the Response MIME Type to application/json
|
||||
var config = new GenerationConfig { ResponseMimeType = "application/json" };
|
||||
var request = new GenerateContentRequest(prompt, config);
|
||||
request.AddMedia(base64Image, "image/png");
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
// 3. Use System.Text.Json to turn that string back into our DTO
|
||||
var options = new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||
var result = System.Text.Json.JsonSerializer.Deserialize<RecipeResponseDto>(response.Text, options);
|
||||
|
||||
return result ?? new RecipeResponseDto { Title = "Error parsing JSON" };
|
||||
}
|
||||
}
|
||||
50
.vscode-server/data/User/History/b03096/Tt28.cs
Normal file
50
.vscode-server/data/User/History/b03096/Tt28.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// Use the library's internal GenerateContentRequest but manually build the Parts list
|
||||
var request = new GenerateContentRequest();
|
||||
var content = new Content(Role.User);
|
||||
|
||||
// This is the specific syntax to satisfy the IPart list requirement
|
||||
content.Parts = new List<IPart>
|
||||
{
|
||||
new Part { Text = prompt },
|
||||
new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
}.Cast<IPart>().ToList(); // This 'Cast' is the magic bullet
|
||||
|
||||
request.Contents = new List<Content> { content };
|
||||
|
||||
// Solve the ambiguity by picking the Request overload
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
56
.vscode-server/data/User/History/b03096/WeNg.cs
Normal file
56
.vscode-server/data/User/History/b03096/WeNg.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
// Use a string for the model name to avoid CS0117
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// Use the constructor that the library likes
|
||||
var request = new GenerateContentRequest();
|
||||
|
||||
// Manually build the structure in a way that avoids the List conversion crash
|
||||
var content = new Content(Role.User);
|
||||
|
||||
// We add the text part using the library's preferred text-first approach
|
||||
request.Contents = new List<Content> { content };
|
||||
|
||||
// Attempting the most universal "Add" method for media
|
||||
// If your library doesn't have AddMedia, we use this direct property:
|
||||
content.Parts = new List<IPart>
|
||||
{
|
||||
new TextPart(prompt),
|
||||
new InlineDataPart("image/png", base64Image)
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
47
.vscode-server/data/User/History/b03096/XLsh.cs
Normal file
47
.vscode-server/data/User/History/b03096/XLsh.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI; // Add this!
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
// Get the key from your user-secrets
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
// 1. Initialize Gemini
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel(Model.Gemini15Flash);
|
||||
|
||||
// 2. Convert the uploaded image to a format Gemini understands
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
// 3. The "Magic" Prompt
|
||||
var prompt = "Extract the recipe from this image. Return ONLY a JSON object with: title (string), description (string), ingredients (array of strings), and instructions (array of strings).";
|
||||
|
||||
// 4. Call Gemini
|
||||
var response = await model.GenerateContent(new List<Part> {
|
||||
new TextPart { Text = prompt },
|
||||
new InlineDataPart { MimeType = "image/jpeg", Data = base64Image }
|
||||
});
|
||||
|
||||
// 5. Parse the AI's response (simplified for now)
|
||||
var aiText = response.Text;
|
||||
|
||||
// For now, let's return the AI text in our DTO
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "AI Decoded Recipe",
|
||||
Description = aiText, // The raw AI response
|
||||
Ingredients = new List<string> { "Check description for details" }
|
||||
};
|
||||
}
|
||||
}
|
||||
53
.vscode-server/data/User/History/b03096/ZxdS.cs
Normal file
53
.vscode-server/data/User/History/b03096/ZxdS.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// 1. Create the parts using the IPart interface
|
||||
var parts = new List<IPart>
|
||||
{
|
||||
new TextPart { Text = prompt },
|
||||
new InlineDataPart { MimeType = "image/png", Data = base64Image }
|
||||
};
|
||||
|
||||
// 2. Create Content using the constructor (to fix CS1729)
|
||||
var content = new Content(parts, Role.User);
|
||||
|
||||
// 3. Create the Request
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
// 4. Call the model
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
24
.vscode-server/data/User/History/b03096/dXqj.cs
Normal file
24
.vscode-server/data/User/History/b03096/dXqj.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public interface IRecipeService
|
||||
{
|
||||
Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image);
|
||||
}
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
// For now, this is a "Mock" service.
|
||||
// Later, we will add the Gemini API call here.
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "AI Generated Recipe",
|
||||
Description = "Successfully parsed from the image.",
|
||||
Ingredients = new List<string> { "Example Ingredient 1", "Example Ingredient 2" },
|
||||
Instructions = new List<string> { "Step 1: Mix everything", "Step 2: Cook it" }
|
||||
};
|
||||
}
|
||||
}
|
||||
57
.vscode-server/data/User/History/b03096/dZC4.cs
Normal file
57
.vscode-server/data/User/History/b03096/dZC4.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// We create the request using 'dynamic' to skip the IPart/Part conversion errors
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content>
|
||||
{
|
||||
new Content
|
||||
{
|
||||
Role = Role.User,
|
||||
// We cast the list to dynamic so the compiler doesn't check the 'Part' types
|
||||
Parts = (dynamic)new List<object>
|
||||
{
|
||||
new { text = prompt },
|
||||
new { inline_data = new { mime_type = "image/png", data = base64Image } }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Call the model with our request
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
52
.vscode-server/data/User/History/b03096/dxLf.cs
Normal file
52
.vscode-server/data/User/History/b03096/dxLf.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// Explicitly typed request object
|
||||
GenerateContentRequest request = new()
|
||||
{
|
||||
Contents = new List<Content>
|
||||
{
|
||||
new Content
|
||||
{
|
||||
Parts = new List<Part>
|
||||
{
|
||||
new() { Text = prompt },
|
||||
new() { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent((GenerateContentRequest)request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
1
.vscode-server/data/User/History/b03096/entries.json
Normal file
1
.vscode-server/data/User/History/b03096/entries.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version":1,"resource":"vscode-remote://ssh-remote%2B10.0.11.3/home/chloe/Seasoned.Backend/Services/RecipeService.cs","entries":[{"id":"dXqj.cs","timestamp":1772653693352},{"id":"77Sz.cs","timestamp":1772653852608},{"id":"XLsh.cs","timestamp":1772655862562},{"id":"vh2Y.cs","timestamp":1772657163089},{"id":"J28Z.cs","timestamp":1772657199088},{"id":"Goe4.cs","timestamp":1772657272583},{"id":"dxLf.cs","timestamp":1772657432564},{"id":"r1gL.cs","timestamp":1772657455148},{"id":"ZxdS.cs","timestamp":1772657509246},{"id":"sqBf.cs","timestamp":1772657543478},{"id":"DZeF.cs","timestamp":1772657595090},{"id":"Gr2p.cs","timestamp":1772657644181},{"id":"2oaa.cs","timestamp":1772657722505},{"id":"4GWQ.cs","timestamp":1772657735239},{"id":"GoWQ.cs","timestamp":1772657762861},{"id":"euIa.cs","timestamp":1772658484116},{"id":"Tt28.cs","timestamp":1772659259080},{"id":"y3ZY.cs","timestamp":1772659286185},{"id":"ik8E.cs","timestamp":1772659373055},{"id":"dZC4.cs","timestamp":1772659424718},{"id":"26Rk.cs","timestamp":1772659464758},{"id":"yxfK.cs","timestamp":1772659765699},{"id":"WeNg.cs","timestamp":1772659813242},{"id":"MbC8.cs","timestamp":1772659856530},{"id":"gr1X.cs","timestamp":1772659909009},{"id":"BJsp.cs","timestamp":1772660249541},{"id":"Smgs.cs","timestamp":1772660613374}]}
|
||||
51
.vscode-server/data/User/History/b03096/euIa.cs
Normal file
51
.vscode-server/data/User/History/b03096/euIa.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// We create the request using the library's internal 'Content' structure
|
||||
// but we add the parts as simple objects to avoid the IPart cast crash.
|
||||
var content = new Content(Role.User);
|
||||
content.Parts = new List<IPart>();
|
||||
|
||||
// Instead of 'new Part', we use the specific Part types provided by the library
|
||||
// that are GUARANTEED to implement IPart correctly.
|
||||
content.Parts.Add(new TextPart { Text = prompt });
|
||||
content.Parts.Add(new InlineDataPart { MimeType = "image/png", Data = base64Image });
|
||||
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
45
.vscode-server/data/User/History/b03096/gr1X.cs
Normal file
45
.vscode-server/data/User/History/b03096/gr1X.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
|
||||
// THE FIX: Convert bytes to a Base64 string for the AddMedia method
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
var request = new GenerateContentRequest(prompt);
|
||||
|
||||
// This matches the (string, string) signature the compiler is looking for
|
||||
request.AddMedia(base64Image, "image/png");
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
38
.vscode-server/data/User/History/b03096/ik8E.cs
Normal file
38
.vscode-server/data/User/History/b03096/ik8E.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var imageBytes = ms.ToArray();
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
var response = await model.GenerateContent(prompt, imageBytes, "image/png");
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
51
.vscode-server/data/User/History/b03096/r1gL.cs
Normal file
51
.vscode-server/data/User/History/b03096/r1gL.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
GenerateContentRequest request = new()
|
||||
{
|
||||
Contents = new List<Content>
|
||||
{
|
||||
new Content
|
||||
{
|
||||
Parts = new List<Part>
|
||||
{
|
||||
new() { Text = prompt },
|
||||
new() { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent((GenerateContentRequest)request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
56
.vscode-server/data/User/History/b03096/sqBf.cs
Normal file
56
.vscode-server/data/User/History/b03096/sqBf.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// Use the base Part class with property initializers
|
||||
var parts = new List<Part>
|
||||
{
|
||||
new Part { Text = prompt },
|
||||
new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
};
|
||||
|
||||
// Use the default constructor and set properties
|
||||
var content = new Content
|
||||
{
|
||||
Role = Role.User,
|
||||
Parts = parts
|
||||
};
|
||||
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content> { content }
|
||||
};
|
||||
|
||||
// Casting to solve the ambiguity error we saw earlier
|
||||
var response = await model.GenerateContent((GenerateContentRequest)request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
54
.vscode-server/data/User/History/b03096/vh2Y.cs
Normal file
54
.vscode-server/data/User/History/b03096/vh2Y.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("GeminiApiKey missing in secrets");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
// Using the 2.5 Flash model specifically
|
||||
var model = googleAI.GenerativeModel(Model.Gemini25Flash);
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract this recipe. Provide a title and description.";
|
||||
|
||||
// This structure ensures the 2.5 model receives both the text and the image correctly
|
||||
var request = new GenerateContentRequest
|
||||
{
|
||||
Contents = new List<Content>
|
||||
{
|
||||
new Content
|
||||
{
|
||||
Role = Role.User,
|
||||
Parts = new List<Part>
|
||||
{
|
||||
new TextPart { Text = prompt },
|
||||
new InlineDataPart { MimeType = "image/png", Data = base64Image }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
51
.vscode-server/data/User/History/b03096/y3ZY.cs
Normal file
51
.vscode-server/data/User/History/b03096/y3ZY.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using System.Linq;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel("gemini-2.5-flash");
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var base64Image = Convert.ToBase64String(ms.ToArray());
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// Use the library's internal GenerateContentRequest but manually build the Parts list
|
||||
var request = new GenerateContentRequest();
|
||||
var content = new Content(Role.User);
|
||||
|
||||
// This is the specific syntax to satisfy the IPart list requirement
|
||||
content.Parts = new List<IPart>
|
||||
{
|
||||
new Part { Text = prompt },
|
||||
new Part { InlineData = new InlineData { MimeType = "image/png", Data = base64Image } }
|
||||
}.Cast<IPart>().ToList(); // This 'Cast' is the magic bullet
|
||||
|
||||
request.Contents = new List<Content> { content };
|
||||
|
||||
// Solve the ambiguity by picking the Request overload
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
46
.vscode-server/data/User/History/b03096/yxfK.cs
Normal file
46
.vscode-server/data/User/History/b03096/yxfK.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Seasoned.Backend.DTOs;
|
||||
using Mscc.GenerativeAI;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
|
||||
namespace Seasoned.Backend.Services;
|
||||
|
||||
public class RecipeService : IRecipeService
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
|
||||
public RecipeService(IConfiguration config)
|
||||
{
|
||||
_apiKey = config["GeminiApiKey"] ?? throw new ArgumentNullException("API Key missing");
|
||||
}
|
||||
|
||||
public async Task<RecipeResponseDto> ParseRecipeImageAsync(IFormFile image)
|
||||
{
|
||||
var googleAI = new GoogleAI(_apiKey);
|
||||
var model = googleAI.GenerativeModel(Model.Gemini25Flash);
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
await image.CopyToAsync(ms);
|
||||
var imageBytes = ms.ToArray();
|
||||
|
||||
var prompt = "Extract the recipe from this image. Return Title and Description.";
|
||||
|
||||
// 1. Create the request with just the text prompt first
|
||||
var request = new GenerateContentRequest(prompt);
|
||||
|
||||
// 2. Use the built-in AddMedia helper.
|
||||
// This automatically handles the IPart/InlineData wrapping for you!
|
||||
request.AddMedia(imageBytes, "image/png");
|
||||
|
||||
// 3. Send the request
|
||||
var response = await model.GenerateContent(request);
|
||||
|
||||
return new RecipeResponseDto
|
||||
{
|
||||
Title = "Gemini 2.5 Analysis",
|
||||
Description = response.Text ?? "No text returned",
|
||||
Ingredients = new List<string>(),
|
||||
Instructions = new List<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
unset NODE_OPTIONS
|
||||
ELECTRON_RUN_AS_NODE=1 "/home/chloe/.vscode-server/cli/servers/Stable-072586267e68ece9a47aa43f8c108e0dcbf44622/server/node" "/home/chloe/.vscode-server/data/User/globalStorage/github.copilot-chat/copilotCli/copilotCLIShim.js" "$@"
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,219 @@
|
||||
#---------------------------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
#---------------------------------------------------------------------------------------------
|
||||
|
||||
# Windows GitHub Copilot CLI bootstrapper
|
||||
#
|
||||
# Responsibilities:
|
||||
# 1. Locate the real Copilot CLI binary (avoid recursion if this file shadows it).
|
||||
# 2. Offer to install if missing (npm -g @github/copilot).
|
||||
# 3. Enforce minimum version (>= REQUIRED_VERSION) with interactive update.
|
||||
# 4. Execute the real binary with original arguments and exit with its status.
|
||||
#
|
||||
# NOTE: This file intentionally keeps logic self‑contained (no external deps) so it can be dropped into PATH directly.
|
||||
|
||||
# Minimum required Copilot CLI version
|
||||
$RequiredVersion = "0.0.394"
|
||||
$PackageName = "@github/copilot"
|
||||
|
||||
function Invoke-NpmGlobalCommand {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][ValidateSet('install', 'update')][string]$Command,
|
||||
[Parameter(Mandatory = $true)][string]$Package
|
||||
)
|
||||
|
||||
$npmArgs = @($Command, '-g', $Package)
|
||||
|
||||
$npmCmd = Get-Command npm.cmd -ErrorAction SilentlyContinue
|
||||
if ($npmCmd) {
|
||||
& npm.cmd @npmArgs
|
||||
} else {
|
||||
& npm @npmArgs
|
||||
}
|
||||
}
|
||||
|
||||
function Find-RealCopilot {
|
||||
# Find the real copilot binary, avoiding this script if it's in PATH
|
||||
$CurrentScript = $MyInvocation.PSCommandPath
|
||||
if (-not $CurrentScript) { $CurrentScript = $PSCommandPath }
|
||||
$CopilotPath = (Get-Command copilot -ErrorAction SilentlyContinue).Source
|
||||
|
||||
# Check if the copilot command would point to this script
|
||||
$CurrentScriptResolved = if ($CurrentScript) { (Resolve-Path $CurrentScript -ErrorAction SilentlyContinue).Path } else { $null }
|
||||
$CopilotPathResolved = if ($CopilotPath) { (Resolve-Path $CopilotPath -ErrorAction SilentlyContinue).Path } else { $null }
|
||||
|
||||
if ($CurrentScript -eq $CopilotPath -or (Split-Path $CurrentScript -Parent) -eq (Split-Path $CopilotPath -Parent) -or ($CurrentScriptResolved -and $CopilotPathResolved -and $CurrentScriptResolved -eq $CopilotPathResolved)) {
|
||||
# The copilot in PATH is this script, find the real one by temporarily removing this script's directory from PATH
|
||||
$ScriptDir = Split-Path $CurrentScript -Parent
|
||||
$OldPath = $env:PATH
|
||||
# Use appropriate path delimiter based on OS
|
||||
$PathDelimiter = if ($IsWindows -or $env:OS -eq "Windows_NT") { ';' } else { ':' }
|
||||
$env:PATH = ($env:PATH -split $PathDelimiter | Where-Object { $_ -ne $ScriptDir }) -join $PathDelimiter
|
||||
$RealCopilot = (Get-Command copilot -ErrorAction SilentlyContinue).Source
|
||||
$env:PATH = $OldPath
|
||||
|
||||
if ($RealCopilot -and (Test-Path $RealCopilot)) {
|
||||
return $RealCopilot
|
||||
} else {
|
||||
return $null
|
||||
}
|
||||
} else {
|
||||
# The copilot in PATH is different from this script, use it
|
||||
if ($CopilotPath -and (Test-Path $CopilotPath)) {
|
||||
return $CopilotPath
|
||||
} else {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Test-VersionCompatibility {
|
||||
param([string]$Version)
|
||||
$cleanInstalled = $Version -replace '^v',''
|
||||
$cleanRequired = $RequiredVersion -replace '^v',''
|
||||
try {
|
||||
$installedVer = [version]$cleanInstalled
|
||||
$requiredVer = [version]$cleanRequired
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
return ($installedVer -ge $requiredVer)
|
||||
}
|
||||
|
||||
function Test-AndLaunchCopilot {
|
||||
param([string[]]$Arguments)
|
||||
|
||||
# Check if real copilot command exists
|
||||
$realCopilot = Find-RealCopilot
|
||||
if (-not $realCopilot) {
|
||||
Write-Host "Cannot find GitHub Copilot CLI (https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli)"
|
||||
$answer = Read-Host "Install GitHub Copilot CLI? (y/N)"
|
||||
if ($answer -eq "y" -or $answer -eq "Y") {
|
||||
try {
|
||||
Invoke-NpmGlobalCommand -Command 'install' -Package $PackageName
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Test-AndLaunchCopilot $Arguments
|
||||
return
|
||||
} else {
|
||||
Read-Host "Installation failed. Please check your npm configuration and try again (or run: npm install -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
Read-Host "Installation failed. Please check your npm configuration and try again (or run: npm install -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} else {
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
# Check version compatibility
|
||||
$realCopilot = Find-RealCopilot
|
||||
if (-not $realCopilot) {
|
||||
Write-Host "Error: Unable to find copilot binary."
|
||||
$answer = Read-Host "Would you like to reinstall GitHub Copilot CLI? (y/N)"
|
||||
if ($answer -eq "y" -or $answer -eq "Y") {
|
||||
Write-Host "Reinstalling GitHub Copilot CLI..."
|
||||
try {
|
||||
Invoke-NpmGlobalCommand -Command 'install' -Package $PackageName
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Test-AndLaunchCopilot $Arguments
|
||||
return
|
||||
} else {
|
||||
Read-Host "Reinstallation failed. Please check your npm configuration and try again (or run: npm install -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
Read-Host "Reinstallation failed. Please check your npm configuration and try again (or run: npm install -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} else {
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$versionOutput = & $realCopilot --version 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Command failed"
|
||||
}
|
||||
} catch {
|
||||
# Write-Host "Error: Unable to check copilot version."
|
||||
$answer = Read-Host "Would you like to reinstall GitHub Copilot CLI? (y/N)"
|
||||
if ($answer -eq "y" -or $answer -eq "Y") {
|
||||
try {
|
||||
Invoke-NpmGlobalCommand -Command 'install' -Package $PackageName
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Test-AndLaunchCopilot $Arguments
|
||||
return
|
||||
} else {
|
||||
Read-Host "Reinstallation failed. Please check your npm configuration and try again (or run: npm install -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
Read-Host "Reinstallation failed. Please check your npm configuration and try again (or run: npm install -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} else {
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
# Extract version number from output (search through all lines)
|
||||
$version = $null
|
||||
if ($versionOutput) {
|
||||
foreach ($line in ($versionOutput -split "`n")) {
|
||||
$trimmedLine = $line.Trim()
|
||||
if ($trimmedLine -match '[0-9]+\.[0-9]+\.[0-9]+') {
|
||||
$version = $matches[0]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Command succeeded - assume CLI is installed even if we can't parse the version
|
||||
|
||||
# Only check version compatibility if we have a valid version
|
||||
if ($version -and -not (Test-VersionCompatibility $version)) {
|
||||
Write-Host "GitHub Copilot CLI version $version is not compatible."
|
||||
Write-Host "Version $RequiredVersion or later is required."
|
||||
$answer = Read-Host "Update GitHub Copilot CLI? (y/N)"
|
||||
if ($answer -eq "y" -or $answer -eq "Y") {
|
||||
try {
|
||||
Invoke-NpmGlobalCommand -Command 'update' -Package $PackageName
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Test-AndLaunchCopilot $Arguments
|
||||
return
|
||||
} else {
|
||||
Read-Host "Update failed. Please check your npm configuration and try again (or run: npm update -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
Read-Host "Update failed. Please check your npm configuration and try again (or run: npm update -g @github/copilot)."
|
||||
return
|
||||
}
|
||||
} else {
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
# All checks passed, execute the real copilot binary
|
||||
$realCopilot = Find-RealCopilot
|
||||
if ($realCopilot -and (Test-Path $realCopilot)) {
|
||||
& $realCopilot @Arguments
|
||||
} else {
|
||||
Write-Host "Error: Could not find the real GitHub Copilot CLI binary"
|
||||
Read-Host "Please ensure it's properly installed with: npm install -g @github/copilot"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# Start the check and launch process
|
||||
$finalArgs = $args
|
||||
# Handle --clear argument
|
||||
if ($args.Length -gt 0 -and $args[0] -eq '--clear') {
|
||||
Clear-Host
|
||||
$finalArgs = $args[1..($args.Length - 1)]
|
||||
}
|
||||
|
||||
Test-AndLaunchCopilot $finalArgs
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
unset NODE_OPTIONS
|
||||
ELECTRON_RUN_AS_NODE=1 "/home/chloe/.vscode-server/cli/servers/Stable-072586267e68ece9a47aa43f8c108e0dcbf44622/server/node" "/home/chloe/.vscode-server/data/User/globalStorage/github.copilot-chat/debugCommand/copilotDebugCommand.js" "vscode://github.copilot-chat" "code --openExternal " "$@"
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,108 @@
|
||||
---
|
||||
name: Plan
|
||||
description: Researches and outlines multi-step plans
|
||||
argument-hint: Outline the goal or problem to research
|
||||
target: vscode
|
||||
disable-model-invocation: true
|
||||
tools: ['agent', 'search', 'read', 'execute/getTerminalOutput', 'execute/testFailure', 'web', 'github/issue_read', 'github.vscode-pull-request-github/issue_fetch', 'github.vscode-pull-request-github/activePullRequest', 'vscode/askQuestions']
|
||||
agents: []
|
||||
handoffs:
|
||||
- label: Start Implementation
|
||||
agent: agent
|
||||
prompt: 'Start implementation'
|
||||
send: true
|
||||
- label: Open in Editor
|
||||
agent: agent
|
||||
prompt: '#createFile the plan as is into an untitled file (`untitled:plan-${camelCaseName}.prompt.md` without frontmatter) for further refinement.'
|
||||
send: true
|
||||
showContinueOn: false
|
||||
---
|
||||
You are a PLANNING AGENT, pairing with the user to create a detailed, actionable plan.
|
||||
|
||||
Your job: research the codebase → clarify with the user → produce a comprehensive plan. This iterative approach catches edge cases and non-obvious requirements BEFORE implementation begins.
|
||||
|
||||
Your SOLE responsibility is planning. NEVER start implementation.
|
||||
|
||||
<rules>
|
||||
- STOP if you consider running file editing tools — plans are for others to execute
|
||||
- Use #tool:vscode/askQuestions freely to clarify requirements — don't make large assumptions
|
||||
- Present a well-researched plan with loose ends tied BEFORE implementation
|
||||
</rules>
|
||||
|
||||
<workflow>
|
||||
Cycle through these phases based on user input. This is iterative, not linear.
|
||||
|
||||
## 1. Discovery
|
||||
|
||||
Run #tool:agent/runSubagent to gather context and discover potential blockers or ambiguities.
|
||||
|
||||
MANDATORY: Instruct the subagent to work autonomously following <research_instructions>.
|
||||
|
||||
<research_instructions>
|
||||
- Research the user's task comprehensively using read-only tools.
|
||||
- Start with high-level code searches before reading specific files.
|
||||
- Pay special attention to instructions and skills made available by the developers to understand best practices and intended usage.
|
||||
- Identify missing information, conflicting requirements, or technical unknowns.
|
||||
- DO NOT draft a full plan yet — focus on discovery and feasibility.
|
||||
</research_instructions>
|
||||
|
||||
After the subagent returns, analyze the results.
|
||||
|
||||
## 2. Alignment
|
||||
|
||||
If research reveals major ambiguities or if you need to validate assumptions:
|
||||
- Use #tool:vscode/askQuestions to clarify intent with the user.
|
||||
- Surface discovered technical constraints or alternative approaches.
|
||||
- If answers significantly change the scope, loop back to **Discovery**.
|
||||
|
||||
## 3. Design
|
||||
|
||||
Once context is clear, draft a comprehensive implementation plan per <plan_style_guide>.
|
||||
|
||||
The plan should reflect:
|
||||
- Critical file paths discovered during research.
|
||||
- Code patterns and conventions found.
|
||||
- A step-by-step implementation approach.
|
||||
|
||||
Present the plan as a **DRAFT** for review.
|
||||
|
||||
## 4. Refinement
|
||||
|
||||
On user input after showing a draft:
|
||||
- Changes requested → revise and present updated plan.
|
||||
- Questions asked → clarify, or use #tool:vscode/askQuestions for follow-ups.
|
||||
- Alternatives wanted → loop back to **Discovery** with new subagent.
|
||||
- Approval given → acknowledge, the user can now use handoff buttons.
|
||||
|
||||
The final plan should:
|
||||
- Be scannable yet detailed enough to execute.
|
||||
- Include critical file paths and symbol references.
|
||||
- Reference decisions from the discussion.
|
||||
- Leave no ambiguity.
|
||||
|
||||
Keep iterating until explicit approval or handoff.
|
||||
</workflow>
|
||||
|
||||
<plan_style_guide>
|
||||
```markdown
|
||||
## Plan: {Title (2-10 words)}
|
||||
|
||||
{TL;DR — what, how, why. Reference key decisions. (30-200 words, depending on complexity)}
|
||||
|
||||
**Steps**
|
||||
1. {Action with [file](path) links and `symbol` refs}
|
||||
2. {Next step}
|
||||
3. {…}
|
||||
|
||||
**Verification**
|
||||
{How to test: commands, tests, manual checks}
|
||||
|
||||
**Decisions** (if applicable)
|
||||
- {Decision: chose X over Y}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- NO code blocks — describe changes, link to files/symbols
|
||||
- NO questions at the end — ask during workflow via #tool:vscode/askQuestions
|
||||
- Keep scannable
|
||||
</plan_style_guide>
|
||||
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://json.schemastore.org/semantic-release.json",
|
||||
"definitions": {
|
||||
"branch-object": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"channel": {
|
||||
"type": "string"
|
||||
},
|
||||
"range": {
|
||||
"type": "string"
|
||||
},
|
||||
"prerelease": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"extends": {
|
||||
"description": "List of modules or file paths containing a shareable configuration. If multiple shareable configurations are set, they will be imported in the order defined with each configuration option taking precedence over the options defined in a previous shareable configuration",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"branches": {
|
||||
"description": "The branches on which releases should happen.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/branch-object"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/branch-object"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"default": [
|
||||
"+([0-9])?(.{+([0-9]),x}).x",
|
||||
"master",
|
||||
"next",
|
||||
"next-major",
|
||||
{
|
||||
"name": "beta",
|
||||
"prerelease": true
|
||||
},
|
||||
{
|
||||
"name": "alpha",
|
||||
"prerelease": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"repositoryUrl": {
|
||||
"type": "string",
|
||||
"description": "The git repository URL"
|
||||
},
|
||||
"tagFormat": {
|
||||
"type": "string",
|
||||
"description": "The Git tag format used by semantic-release to identify releases. The tag name is generated with Lodash template and will be compiled with the version variable.",
|
||||
"default": "v${version}"
|
||||
},
|
||||
"plugins": {
|
||||
"type": "array",
|
||||
"description": "Define the list of plugins to use. Plugins will run in series, in the order defined",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["path"],
|
||||
"properties": {
|
||||
"path": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/npm",
|
||||
"@semantic-release/github"
|
||||
]
|
||||
},
|
||||
"dryRun": {
|
||||
"type": "boolean",
|
||||
"description": "The objective of the dry-run mode is to get a preview of the pending release. Dry-run mode skips the following steps: prepare, publish, success and fail. In addition to this it prints the next version and release notes to the console"
|
||||
},
|
||||
"ci": {
|
||||
"type": "boolean",
|
||||
"description": "Set to false to skip Continuous Integration environment verifications. This allows for making releases from a local machine",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"title": "semantic-release Schema",
|
||||
"type": "object"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,433 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://json.schemastore.org/prettierrc.json",
|
||||
"definitions": {
|
||||
"optionsDefinition": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"arrowParens": {
|
||||
"description": "Include parentheses around a sole arrow function parameter.",
|
||||
"default": "always",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["always"],
|
||||
"description": "Always include parens. Example: `(x) => x`"
|
||||
},
|
||||
{
|
||||
"enum": ["avoid"],
|
||||
"description": "Omit parens when possible. Example: `x => x`"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bracketSameLine": {
|
||||
"description": "Put > of opening tags on the last line instead of on a new line.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"bracketSpacing": {
|
||||
"description": "Print spaces between brackets.",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"checkIgnorePragma": {
|
||||
"description": "Check whether the file's first docblock comment contains '@noprettier' or '@noformat' to determine if it should be formatted.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"cursorOffset": {
|
||||
"description": "Print (to stderr) where a cursor at the given position would move to after formatting.",
|
||||
"default": -1,
|
||||
"type": "integer"
|
||||
},
|
||||
"embeddedLanguageFormatting": {
|
||||
"description": "Control how Prettier formats quoted code embedded in the file.",
|
||||
"default": "auto",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["auto"],
|
||||
"description": "Format embedded code if Prettier can automatically identify it."
|
||||
},
|
||||
{
|
||||
"enum": ["off"],
|
||||
"description": "Never automatically format embedded code."
|
||||
}
|
||||
]
|
||||
},
|
||||
"endOfLine": {
|
||||
"description": "Which end of line characters to apply.",
|
||||
"default": "lf",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["lf"],
|
||||
"description": "Line Feed only (\\n), common on Linux and macOS as well as inside git repos"
|
||||
},
|
||||
{
|
||||
"enum": ["crlf"],
|
||||
"description": "Carriage Return + Line Feed characters (\\r\\n), common on Windows"
|
||||
},
|
||||
{
|
||||
"enum": ["cr"],
|
||||
"description": "Carriage Return character only (\\r), used very rarely"
|
||||
},
|
||||
{
|
||||
"enum": ["auto"],
|
||||
"description": "Maintain existing\n(mixed values within one file are normalised by looking at what's used after the first line)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"experimentalOperatorPosition": {
|
||||
"description": "Where to print operators when binary expressions wrap lines.",
|
||||
"default": "end",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["start"],
|
||||
"description": "Print operators at the start of new lines."
|
||||
},
|
||||
{
|
||||
"enum": ["end"],
|
||||
"description": "Print operators at the end of previous lines."
|
||||
}
|
||||
]
|
||||
},
|
||||
"experimentalTernaries": {
|
||||
"description": "Use curious ternaries, with the question mark after the condition.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"filepath": {
|
||||
"description": "Specify the input filepath. This will be used to do parser inference.",
|
||||
"type": "string"
|
||||
},
|
||||
"htmlWhitespaceSensitivity": {
|
||||
"description": "How to handle whitespaces in HTML.",
|
||||
"default": "css",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["css"],
|
||||
"description": "Respect the default value of CSS display property."
|
||||
},
|
||||
{
|
||||
"enum": ["strict"],
|
||||
"description": "Whitespaces are considered sensitive."
|
||||
},
|
||||
{
|
||||
"enum": ["ignore"],
|
||||
"description": "Whitespaces are considered insensitive."
|
||||
}
|
||||
]
|
||||
},
|
||||
"insertPragma": {
|
||||
"description": "Insert @format pragma into file's first docblock comment.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"jsxSingleQuote": {
|
||||
"description": "Use single quotes in JSX.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"objectWrap": {
|
||||
"description": "How to wrap object literals.",
|
||||
"default": "preserve",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["preserve"],
|
||||
"description": "Keep as multi-line, if there is a newline between the opening brace and first property."
|
||||
},
|
||||
{
|
||||
"enum": ["collapse"],
|
||||
"description": "Fit to a single line when possible."
|
||||
}
|
||||
]
|
||||
},
|
||||
"parser": {
|
||||
"description": "Which parser to use.",
|
||||
"anyOf": [
|
||||
{
|
||||
"enum": ["flow"],
|
||||
"description": "Flow"
|
||||
},
|
||||
{
|
||||
"enum": ["babel"],
|
||||
"description": "JavaScript"
|
||||
},
|
||||
{
|
||||
"enum": ["babel-flow"],
|
||||
"description": "Flow"
|
||||
},
|
||||
{
|
||||
"enum": ["babel-ts"],
|
||||
"description": "TypeScript"
|
||||
},
|
||||
{
|
||||
"enum": ["typescript"],
|
||||
"description": "TypeScript"
|
||||
},
|
||||
{
|
||||
"enum": ["acorn"],
|
||||
"description": "JavaScript"
|
||||
},
|
||||
{
|
||||
"enum": ["espree"],
|
||||
"description": "JavaScript"
|
||||
},
|
||||
{
|
||||
"enum": ["meriyah"],
|
||||
"description": "JavaScript"
|
||||
},
|
||||
{
|
||||
"enum": ["css"],
|
||||
"description": "CSS"
|
||||
},
|
||||
{
|
||||
"enum": ["less"],
|
||||
"description": "Less"
|
||||
},
|
||||
{
|
||||
"enum": ["scss"],
|
||||
"description": "SCSS"
|
||||
},
|
||||
{
|
||||
"enum": ["json"],
|
||||
"description": "JSON"
|
||||
},
|
||||
{
|
||||
"enum": ["json5"],
|
||||
"description": "JSON5"
|
||||
},
|
||||
{
|
||||
"enum": ["jsonc"],
|
||||
"description": "JSON with Comments"
|
||||
},
|
||||
{
|
||||
"enum": ["json-stringify"],
|
||||
"description": "JSON.stringify"
|
||||
},
|
||||
{
|
||||
"enum": ["graphql"],
|
||||
"description": "GraphQL"
|
||||
},
|
||||
{
|
||||
"enum": ["markdown"],
|
||||
"description": "Markdown"
|
||||
},
|
||||
{
|
||||
"enum": ["mdx"],
|
||||
"description": "MDX"
|
||||
},
|
||||
{
|
||||
"enum": ["vue"],
|
||||
"description": "Vue"
|
||||
},
|
||||
{
|
||||
"enum": ["yaml"],
|
||||
"description": "YAML"
|
||||
},
|
||||
{
|
||||
"enum": ["glimmer"],
|
||||
"description": "Ember / Handlebars"
|
||||
},
|
||||
{
|
||||
"enum": ["html"],
|
||||
"description": "HTML"
|
||||
},
|
||||
{
|
||||
"enum": ["angular"],
|
||||
"description": "Angular"
|
||||
},
|
||||
{
|
||||
"enum": ["lwc"],
|
||||
"description": "Lightning Web Components"
|
||||
},
|
||||
{
|
||||
"enum": ["mjml"],
|
||||
"description": "MJML"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Custom parser"
|
||||
}
|
||||
]
|
||||
},
|
||||
"plugins": {
|
||||
"description": "Add a plugin. Multiple plugins can be passed as separate `--plugin`s.",
|
||||
"default": [],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"printWidth": {
|
||||
"description": "The line length where Prettier will try wrap.",
|
||||
"default": 80,
|
||||
"type": "integer"
|
||||
},
|
||||
"proseWrap": {
|
||||
"description": "How to wrap prose.",
|
||||
"default": "preserve",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["always"],
|
||||
"description": "Wrap prose if it exceeds the print width."
|
||||
},
|
||||
{
|
||||
"enum": ["never"],
|
||||
"description": "Do not wrap prose."
|
||||
},
|
||||
{
|
||||
"enum": ["preserve"],
|
||||
"description": "Wrap prose as-is."
|
||||
}
|
||||
]
|
||||
},
|
||||
"quoteProps": {
|
||||
"description": "Change when properties in objects are quoted.",
|
||||
"default": "as-needed",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["as-needed"],
|
||||
"description": "Only add quotes around object properties where required."
|
||||
},
|
||||
{
|
||||
"enum": ["consistent"],
|
||||
"description": "If at least one property in an object requires quotes, quote all properties."
|
||||
},
|
||||
{
|
||||
"enum": ["preserve"],
|
||||
"description": "Respect the input use of quotes in object properties."
|
||||
}
|
||||
]
|
||||
},
|
||||
"rangeEnd": {
|
||||
"description": "Format code ending at a given character offset (exclusive).\nThe range will extend forwards to the end of the selected statement.",
|
||||
"default": null,
|
||||
"type": "integer"
|
||||
},
|
||||
"rangeStart": {
|
||||
"description": "Format code starting at a given character offset.\nThe range will extend backwards to the start of the first line containing the selected statement.",
|
||||
"default": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"requirePragma": {
|
||||
"description": "Require either '@prettier' or '@format' to be present in the file's first docblock comment in order for it to be formatted.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"semi": {
|
||||
"description": "Print semicolons.",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"singleAttributePerLine": {
|
||||
"description": "Enforce single attribute per line in HTML, Vue and JSX.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"singleQuote": {
|
||||
"description": "Use single quotes instead of double quotes.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"tabWidth": {
|
||||
"description": "Number of spaces per indentation level.",
|
||||
"default": 2,
|
||||
"type": "integer"
|
||||
},
|
||||
"trailingComma": {
|
||||
"description": "Print trailing commas wherever possible when multi-line.",
|
||||
"default": "all",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": ["all"],
|
||||
"description": "Trailing commas wherever possible (including function arguments)."
|
||||
},
|
||||
{
|
||||
"enum": ["es5"],
|
||||
"description": "Trailing commas where valid in ES5 (objects, arrays, etc.)"
|
||||
},
|
||||
{
|
||||
"enum": ["none"],
|
||||
"description": "No trailing commas."
|
||||
}
|
||||
]
|
||||
},
|
||||
"useTabs": {
|
||||
"description": "Indent with tabs instead of spaces.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"vueIndentScriptAndStyle": {
|
||||
"description": "Indent script and style tags in Vue files.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"overridesDefinition": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"overrides": {
|
||||
"type": "array",
|
||||
"description": "Provide a list of patterns to override prettier configuration.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["files"],
|
||||
"properties": {
|
||||
"files": {
|
||||
"description": "Include these files in this override.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"excludeFiles": {
|
||||
"description": "Exclude these files from this override.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"$ref": "#/definitions/optionsDefinition",
|
||||
"type": "object",
|
||||
"description": "The options to apply for this override."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/optionsDefinition"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/overridesDefinition"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"title": "Schema for .prettierrc"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,405 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://json.schemastore.org/jscpd.json",
|
||||
"additionalProperties": false,
|
||||
"definitions": {
|
||||
"colorPreset": {
|
||||
"enum": [
|
||||
"green",
|
||||
"blue",
|
||||
"red",
|
||||
"yellow",
|
||||
"orange",
|
||||
"purple",
|
||||
"pink",
|
||||
"grey",
|
||||
"gray",
|
||||
"cyan",
|
||||
"black"
|
||||
]
|
||||
},
|
||||
"colorHex": {
|
||||
"type": "string",
|
||||
"pattern": "([0-9a-fA-F]{3}){1,2}"
|
||||
},
|
||||
"color": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/colorPreset"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/colorHex"
|
||||
}
|
||||
]
|
||||
},
|
||||
"format": {
|
||||
"enum": [
|
||||
"abap",
|
||||
"actionscript",
|
||||
"ada",
|
||||
"apacheconf",
|
||||
"apl",
|
||||
"applescript",
|
||||
"arduino",
|
||||
"arff",
|
||||
"asciidoc",
|
||||
"asm6502",
|
||||
"aspnet",
|
||||
"autohotkey",
|
||||
"autoit",
|
||||
"bash",
|
||||
"basic",
|
||||
"batch",
|
||||
"bison",
|
||||
"brainfuck",
|
||||
"bro",
|
||||
"c",
|
||||
"c-header",
|
||||
"clike",
|
||||
"clojure",
|
||||
"coffeescript",
|
||||
"comments",
|
||||
"cpp",
|
||||
"cpp-header",
|
||||
"crystal",
|
||||
"csharp",
|
||||
"csp",
|
||||
"css-extras",
|
||||
"css",
|
||||
"d",
|
||||
"dart",
|
||||
"diff",
|
||||
"django",
|
||||
"docker",
|
||||
"eiffel",
|
||||
"elixir",
|
||||
"elm",
|
||||
"erb",
|
||||
"erlang",
|
||||
"flow",
|
||||
"fortran",
|
||||
"fsharp",
|
||||
"gedcom",
|
||||
"gherkin",
|
||||
"git",
|
||||
"glsl",
|
||||
"go",
|
||||
"graphql",
|
||||
"groovy",
|
||||
"haml",
|
||||
"handlebars",
|
||||
"haskell",
|
||||
"haxe",
|
||||
"hpkp",
|
||||
"hsts",
|
||||
"http",
|
||||
"ichigojam",
|
||||
"icon",
|
||||
"inform7",
|
||||
"ini",
|
||||
"io",
|
||||
"j",
|
||||
"java",
|
||||
"javascript",
|
||||
"jolie",
|
||||
"json",
|
||||
"jsx",
|
||||
"julia",
|
||||
"keymap",
|
||||
"kotlin",
|
||||
"latex",
|
||||
"less",
|
||||
"liquid",
|
||||
"lisp",
|
||||
"livescript",
|
||||
"lolcode",
|
||||
"lua",
|
||||
"makefile",
|
||||
"markdown",
|
||||
"markup",
|
||||
"matlab",
|
||||
"mel",
|
||||
"mizar",
|
||||
"monkey",
|
||||
"n4js",
|
||||
"nasm",
|
||||
"nginx",
|
||||
"nim",
|
||||
"nix",
|
||||
"nsis",
|
||||
"objectivec",
|
||||
"ocaml",
|
||||
"opencl",
|
||||
"oz",
|
||||
"parigp",
|
||||
"pascal",
|
||||
"perl",
|
||||
"php",
|
||||
"plsql",
|
||||
"powershell",
|
||||
"processing",
|
||||
"prolog",
|
||||
"properties",
|
||||
"protobuf",
|
||||
"pug",
|
||||
"puppet",
|
||||
"pure",
|
||||
"python",
|
||||
"q",
|
||||
"qore",
|
||||
"r",
|
||||
"reason",
|
||||
"renpy",
|
||||
"rest",
|
||||
"rip",
|
||||
"roboconf",
|
||||
"ruby",
|
||||
"rust",
|
||||
"sas",
|
||||
"sass",
|
||||
"scala",
|
||||
"scheme",
|
||||
"scss",
|
||||
"smalltalk",
|
||||
"smarty",
|
||||
"soy",
|
||||
"sql",
|
||||
"stylus",
|
||||
"swift",
|
||||
"tap",
|
||||
"tcl",
|
||||
"textile",
|
||||
"tsx",
|
||||
"tt2",
|
||||
"twig",
|
||||
"typescript",
|
||||
"vbnet",
|
||||
"velocity",
|
||||
"verilog",
|
||||
"vhdl",
|
||||
"vim",
|
||||
"visual-basic",
|
||||
"wasm",
|
||||
"url",
|
||||
"wiki",
|
||||
"xeora",
|
||||
"xojo",
|
||||
"xquery",
|
||||
"yaml"
|
||||
]
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"minLines": {
|
||||
"type": "integer",
|
||||
"default": 5,
|
||||
"description": "minimum size of code block in lines to check for duplication"
|
||||
},
|
||||
"maxLines": {
|
||||
"type": "integer",
|
||||
"default": 1000,
|
||||
"description": "maximum size of source file in lines to check for duplication"
|
||||
},
|
||||
"maxSize": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^\\+?[0-9]+(\\.[0-9]+)? *[kKmMgGtTpP][bB]$"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
],
|
||||
"default": "100kb",
|
||||
"description": "maximum size of source file in bytes to check for duplication (e.g.,: 1kb, 1mb, 120kb)"
|
||||
},
|
||||
"minTokens": {
|
||||
"type": "integer",
|
||||
"default": 50,
|
||||
"description": "minimum size of code block in tokens to check for duplication"
|
||||
},
|
||||
"threshold": {
|
||||
"type": "number",
|
||||
"description": "maximum allowed duplicate lines expressed as a percentage; exit with error and exit code 1 when threshold exceeded"
|
||||
},
|
||||
"formatsExts": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"default": {},
|
||||
"description": "custom mapping from formats to file extensions (default: https://github.com/kucherenko/jscpd/blob/master/packages/tokenizer/src/formats.ts); see https://github.com/kucherenko/jscpd/blob/master/supported_formats.md"
|
||||
},
|
||||
"output": {
|
||||
"type": "string",
|
||||
"default": "./report",
|
||||
"description": "path to directory for non-console reports"
|
||||
},
|
||||
"path": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "paths that should be included in duplicate detection (default: [process.cwd()])"
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"default": "**/*",
|
||||
"description": "glob pattern for files that should be included in duplicate detection (e.g., **/*.txt); only used to filter directories configured via path option"
|
||||
},
|
||||
"ignorePattern": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": [],
|
||||
"description": "ignore code blocks matching these regular expressions"
|
||||
},
|
||||
"mode": {
|
||||
"enum": ["mild", "strict", "weak"],
|
||||
"default": "mild",
|
||||
"description": "mode of detection quality; see https://github.com/kucherenko/jscpd/blob/master/packages/jscpd/README.md#mode"
|
||||
},
|
||||
"ignore": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": [],
|
||||
"description": "glob pattern for files that should be excluded from duplicate detection"
|
||||
},
|
||||
"format": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/format"
|
||||
},
|
||||
"description": "list of formats for which to detect duplication (default: all); see https://github.com/kucherenko/jscpd/blob/master/supported_formats.md"
|
||||
},
|
||||
"store": {
|
||||
"enum": ["leveldb", "redis"],
|
||||
"description": "store used to collect information about code (default: in-memory store); install @jscpd/leveldb-store and use leveldb for big repositories"
|
||||
},
|
||||
"reporters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"enum": [
|
||||
"xml",
|
||||
"json",
|
||||
"csv",
|
||||
"markdown",
|
||||
"consoleFull",
|
||||
"html",
|
||||
"console",
|
||||
"silent",
|
||||
"threshold",
|
||||
"xcode"
|
||||
]
|
||||
},
|
||||
"default": ["console"],
|
||||
"description": "a list of reporters to use to output information about duplication; see https://github.com/kucherenko/jscpd/blob/master/packages/jscpd/README.md#reporters"
|
||||
},
|
||||
"blame": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "get information about authors and dates of duplicated blocks from Git"
|
||||
},
|
||||
"silent": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "do not write duplicate detection progress and result to console"
|
||||
},
|
||||
"verbose": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "show full information during duplicate detection"
|
||||
},
|
||||
"absolute": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "use absolute paths in reports"
|
||||
},
|
||||
"noSymlinks": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "do not follow symlinks"
|
||||
},
|
||||
"skipLocal": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "skip duplicates within folders; just detect cross-folder duplicates"
|
||||
},
|
||||
"ignoreCase": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "ignore case of symbols in code (experimental)"
|
||||
},
|
||||
"gitignore": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "ignore all files from .gitignore file"
|
||||
},
|
||||
"reportersOptions": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"badge": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "output path for duplication level badge (default: path.join(output, 'jscpd-badge.svg'))"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"default": "Copy/Paste",
|
||||
"description": "badge subject text (URL-encoding needed for spaces or special characters)"
|
||||
},
|
||||
"labelColor": {
|
||||
"$ref": "#/definitions/color",
|
||||
"default": "555",
|
||||
"description": "badge label color (name or RGB code without #); see https://github.com/badgen/badgen/blob/master/src/color-presets.ts"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "badge value text (URL-encoding needed for spaces or special characters, default: duplication %)"
|
||||
},
|
||||
"color": {
|
||||
"$ref": "#/definitions/color",
|
||||
"description": "badge color (name or RGB code without #, default: green if beneath threshold, red if above threshold, grey if threshold not set); see https://github.com/badgen/badgen/blob/master/src/color-presets.ts"
|
||||
},
|
||||
"style": {
|
||||
"enum": ["flat", "classic"],
|
||||
"default": "classic",
|
||||
"description": "badge look: flat or classic"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
"description": "URL for icon to display in front of badge subject text (e.g., data:image/svg+xml;base64,...)"
|
||||
},
|
||||
"iconWidth": {
|
||||
"type": "number",
|
||||
"default": 13,
|
||||
"description": "SVG width of icon to display in front of badge subject text; set this if icon is not square"
|
||||
},
|
||||
"scale": {
|
||||
"type": "number",
|
||||
"default": 1,
|
||||
"description": "size of badge relative to default of 1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"exitCode": {
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"description": "exit code to use when at least one duplicate code block is detected but threshold is not exceeded"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,167 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://json.schemastore.org/ava.json",
|
||||
"additionalProperties": false,
|
||||
"definitions": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"array-of-strings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"array-of-paths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/path"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Configuration Schema for the JavaScript test runner AVA",
|
||||
"properties": {
|
||||
"files": {
|
||||
"$ref": "#/definitions/array-of-paths",
|
||||
"description": "An array of glob patterns to select test files. Files with an underscore prefix are ignored. By default only selects files with `cjs`, `mjs` & `js` extensions, even if the pattern matches other files. Specify `extensions` to allow other file extensions"
|
||||
},
|
||||
"ignoredByWatcher": {
|
||||
"$ref": "#/definitions/array-of-paths",
|
||||
"description": "An array of glob patterns to match files that, even if changed, are ignored by the watcher"
|
||||
},
|
||||
"match": {
|
||||
"$ref": "#/definitions/array-of-paths",
|
||||
"description": "Not typically useful in the `package.json` configuration, but equivalent to specifying `--match` on the CLI"
|
||||
},
|
||||
"cache": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Defaults to `true` to cache compiled files under `node_modules/.cache/ava.` If `false`, files are cached in a temporary directory instead"
|
||||
},
|
||||
"concurrency": {
|
||||
"type": "number",
|
||||
"description": "Max number of test files running at the same time (default: CPU cores)"
|
||||
},
|
||||
"workerThreads": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Use worker threads to run tests (enabled by default). If `false`, tests will run in child processes"
|
||||
},
|
||||
"failFast": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Stop running further tests once a test fails"
|
||||
},
|
||||
"failWithoutAssertions": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "If `false`, does not fail a test if it doesn't run assertions"
|
||||
},
|
||||
"environmentVariables": {
|
||||
"title": "environment variables",
|
||||
"type": "object",
|
||||
"description": "Specifies environment variables to be made available to the tests. The environment variables defined here override the ones from `process.env`",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"serial": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "if `true`, prevents parallel execution of tests within a file"
|
||||
},
|
||||
"tap": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If `true`, enables the TAP reporter"
|
||||
},
|
||||
"verbose": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If `true`, enables verbose output (though currently non-verbose output is not supported)"
|
||||
},
|
||||
"snapshotDir": {
|
||||
"$ref": "#/definitions/path",
|
||||
"description": "Specifies a fixed location for storing snapshot files. Use this if your snapshots are ending up in the wrong location"
|
||||
},
|
||||
"extensions": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/array-of-strings"
|
||||
},
|
||||
{
|
||||
"title": "extensions",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^(c|m)?js$": {
|
||||
"enum": [true]
|
||||
}
|
||||
},
|
||||
"additionalProperties": {
|
||||
"enum": ["commonjs", "module"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"default": ["cjs", "mjs", "js"],
|
||||
"description": "Extensions of test files. Setting this overrides the default `[\"cjs\", \"mjs\", \"js\"]` value, so make sure to include those extensions in the list. Experimentally you can configure how files are loaded"
|
||||
},
|
||||
"require": {
|
||||
"$ref": "#/definitions/array-of-paths",
|
||||
"description": "Extra modules to require before tests are run. Modules are required in the worker processes"
|
||||
},
|
||||
"timeout": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^(\\d+)(s|m)$"
|
||||
}
|
||||
],
|
||||
"default": "10s",
|
||||
"description": "Timeouts in AVA behave differently than in other test frameworks. AVA resets a timer after each test, forcing tests to quit if no new test results were received within the specified timeout. This can be used to handle stalled tests. See our timeout documentation for more options"
|
||||
},
|
||||
"nodeArguments": {
|
||||
"$ref": "#/definitions/array-of-strings",
|
||||
"description": "Configure Node.js arguments used to launch worker processes"
|
||||
},
|
||||
"utilizeParallelBuilds": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "If `false`, disable parallel builds (default: `true`)"
|
||||
},
|
||||
"typescript": {
|
||||
"title": "configuration",
|
||||
"type": "object",
|
||||
"description": "Configures @ava/typescript for projects that precompile TypeScript. Alternatively, you can use `ts-node` to do live testing without transpiling, in which case you shouldn't use the `typescript` property",
|
||||
"properties": {
|
||||
"extensions": {
|
||||
"$ref": "#/definitions/array-of-paths",
|
||||
"default": ["ts"],
|
||||
"description": "You can configure AVA to recognize additional file extensions as TypeScript (e.g., `[\"ts\", \"tsx\"]` to add partial JSX support). Note that the preserve mode for JSX is not (yet) supported. See also AVA's `extensions` object"
|
||||
},
|
||||
"rewritePaths": {
|
||||
"title": "paths",
|
||||
"type": "object",
|
||||
"description": "AVA searches your entire project for `*.js`, `*.cjs`, `*.mjs` and `*.ts` files (or other extensions you've configured). It will ignore such files found in the `rewritePaths` targets (e.g. `build/`). If you use more specific paths, for instance `build/main/`, you may need to change AVA's `files` configuration to ignore other directories. Paths are relative to your project directory",
|
||||
"patternProperties": {
|
||||
"/$": {
|
||||
"type": "string",
|
||||
"pattern": "/$"
|
||||
}
|
||||
}
|
||||
},
|
||||
"compile": {
|
||||
"enum": [false, "tsc"],
|
||||
"default": false,
|
||||
"description": "If `false`, AVA will assume you have already compiled your project. If set to `'tsc'`, AVA will run the TypeScript compiler before running your tests. This can be inefficient when using AVA in watch mode"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "AVA Config Schema",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"pid":3982216,"willReleaseAt":0}
|
||||
Reference in New Issue
Block a user