diff --git a/.gitignore b/.gitignore index 67872c0..f7175a6 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,7 @@ testem.log .DS_Store Thumbs.db - +*.db .nx/cache .nx/workspace-data \ No newline at end of file diff --git a/api/drizzle.config.ts b/api/drizzle.config.ts deleted file mode 100644 index 5b54eef..0000000 --- a/api/drizzle.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig } from "drizzle-kit"; -export default defineConfig({ - dialect: 'sqlite', // 'mysql' | 'sqlite' | 'turso' - schema: './src/db/schema' -}) \ No newline at end of file diff --git a/api/src/app/app.module.ts b/api/src/app/app.module.ts index 9020aed..3590438 100644 --- a/api/src/app/app.module.ts +++ b/api/src/app/app.module.ts @@ -1,10 +1,11 @@ import { Module } from '@nestjs/common'; import { DecksController } from './decks.controller'; import { DrizzleService } from './drizzle.service'; +import { ProxyController } from './proxy.controller'; @Module({ imports: [], - controllers: [DecksController], + controllers: [DecksController,ProxyController], providers: [DrizzleService], }) export class AppModule {} diff --git a/api/src/app/decks.controller.ts b/api/src/app/decks.controller.ts index 9424554..a6a949f 100644 --- a/api/src/app/decks.controller.ts +++ b/api/src/app/decks.controller.ts @@ -1,4 +1,5 @@ // decks.controller.ts +import express from 'express'; import { Controller, Get, @@ -10,8 +11,10 @@ import { Put, HttpException, HttpStatus, + Res, } from '@nestjs/common'; import { DrizzleService } from './drizzle.service'; +import { firstValueFrom } from 'rxjs'; @Controller('decks') export class DecksController { @@ -68,7 +71,7 @@ export class DecksController { const deck = { name: deckname, - images: [], + images: [] as any, }; for (const entry of entries) { @@ -162,4 +165,6 @@ export class DecksController { ) { return this.drizzleService.updateBox(boxId, data); } + + } \ No newline at end of file diff --git a/api/src/app/drizzle.service.ts b/api/src/app/drizzle.service.ts index 001cb24..3c4e7e3 100644 --- a/api/src/app/drizzle.service.ts +++ b/api/src/app/drizzle.service.ts @@ -2,7 +2,7 @@ import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; import { drizzle } from 'drizzle-orm/libsql'; import { Deck, InsertDeck } from '../db/schema'; -import { eq, and } from 'drizzle-orm'; +import { eq, and, isNull } from 'drizzle-orm'; @Injectable() export class DrizzleService { @@ -120,7 +120,7 @@ export class DrizzleService { .select() .from(Deck) .where( - and(eq(Deck.deckname, deck.deckname), eq(Deck.bildid, null)), + and(eq(Deck.deckname, deck.deckname), isNull(Deck.bildid)), ) .all(); diff --git a/api/src/app/proxy.controller.ts b/api/src/app/proxy.controller.ts new file mode 100644 index 0000000..72b90bf --- /dev/null +++ b/api/src/app/proxy.controller.ts @@ -0,0 +1,121 @@ +// decks.controller.ts +import express from 'express'; +import { + Controller, + Get, + Post, + Delete, + Body, + Param, + Query, + Put, + HttpException, + HttpStatus, + Res, +} from '@nestjs/common'; +import { DrizzleService } from './drizzle.service'; +import { firstValueFrom } from 'rxjs'; + +@Controller('') +export class ProxyController { + constructor() {} +// -------------------- + // Proxy Endpoints + // -------------------- +// @Get('debug_image/:name/:filename') +// async getDebugImage( +// @Param('name') name: string, +// @Param('filename') filename: string, +// @Res() res: express.Response, +// ) { +// const url = `http://localhost:8080/api/debug_image/${name}/${filename}`; +// //const url = `http://localhost:5000/api/debug_image/20250112_112306_9286e3bf/thumbnail.jpg`; + +// try { +// // Fetch the image from the external service +// const response = await fetch(url); + +// // Check if the response is OK (status code 200-299) +// if (!response.ok) { +// throw new Error(`Failed to retrieve image: ${response.statusText}`); +// } + +// // Get the image data as a buffer +// const imageBuffer = await response.arrayBuffer(); + +// // Determine the Content-Type based on the file extension +// let contentType = 'image/png'; // Default MIME type +// if (filename.toLowerCase().endsWith('.jpg') || filename.toLowerCase().endsWith('.jpeg')) { +// contentType = 'image/jpeg'; +// } else if (filename.toLowerCase().endsWith('.gif')) { +// contentType = 'image/gif'; +// } else if (filename.toLowerCase().endsWith('.bmp')) { +// contentType = 'image/bmp'; +// } else if (filename.toLowerCase().endsWith('.tiff') || filename.toLowerCase().endsWith('.tif')) { +// contentType = 'image/tiff'; +// } + +// // Set the Content-Type header and send the image data +// res.set('Content-Type', contentType); +// res.send(Buffer.from(imageBuffer)); +// } catch (error) { +// // Handle errors +// res.status(500).json({ error: error.message }); +// } +// } + + @Post('ocr') + async ocrEndpoint( + @Body() data: { image: string }, + @Res() res: express.Response, + ) { + try { + if (!data || !data.image) { + throw new HttpException('No image provided', HttpStatus.BAD_REQUEST); + } + + const response = await fetch('http://localhost:5000/api/ocr', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ image: data.image }), + }); + + const result = await response.json(); + + if (!response.ok) { + if (response.status === 400) { + throw new HttpException(result.error, HttpStatus.BAD_REQUEST); + } + throw new HttpException( + result.error || 'OCR processing failed', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + + // Bei erfolgreicher Verarbeitung mit Warnung + if (result.warning) { + return res.status(HttpStatus.OK).json({ + warning: result.warning, + debug_dir: result.debug_dir, + }); + } + + // Bei vollständig erfolgreicher Verarbeitung + return res.status(HttpStatus.OK).json({ + status: result.status, + results: result.results, + }); + + } catch (error) { + if (error instanceof HttpException) { + throw error; + } + throw new HttpException( + 'Internal server error', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } +} \ No newline at end of file diff --git a/api/src/db/schema.ts b/api/src/db/schema.ts index 952878b..c0d5861 100644 --- a/api/src/db/schema.ts +++ b/api/src/db/schema.ts @@ -3,7 +3,7 @@ import * as t from "drizzle-orm/sqlite-core"; export const Deck = table('Deck', { id: integer('id').primaryKey({ autoIncrement: true }), - deckname: text('deckname'), + deckname: text('deckname').notNull(), bildname: text('bildname'), bildid: text('bildid'), iconindex: integer('iconindex'), diff --git a/api/src/main.ts b/api/src/main.ts index 8bc07e3..d106d8f 100644 --- a/api/src/main.ts +++ b/api/src/main.ts @@ -6,9 +6,12 @@ import { Logger } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app/app.module'; +import { json, urlencoded } from 'express'; async function bootstrap() { const app = await NestFactory.create(AppModule); + app.use(json({ limit: '50mb' })); + app.use(urlencoded({ limit: '50mb', extended: true })); const globalPrefix = 'api'; app.setGlobalPrefix(globalPrefix); const port = process.env['PORT'] || 3000; diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..33af16a --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,10 @@ +import 'dotenv/config'; +import { defineConfig } from 'drizzle-kit'; +export default defineConfig({ + out: './drizzle', + schema: './api/src/db/schema.ts', + dialect: 'sqlite', + dbCredentials: { + url: 'file:local1.db', + }, +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3a2081a..5d9a3ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "dotenv": "^16.4.7", "fabric": "^5.4.1", "flowbite": "^2.5.2", + "http-server": "^14.1.1", "reflect-metadata": "^0.1.13", "rxjs": "~7.8.0", "tslib": "^2.3.0", @@ -50,6 +51,7 @@ "@swc/helpers": "~0.5.11", "@types/fabric": "^5.3.9", "@types/node": "~18.16.9", + "concurrently": "^9.1.2", "drizzle-kit": "^0.30.2", "drizzle-orm": "^0.38.4", "nx": "20.3.1", @@ -10032,7 +10034,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" @@ -10045,7 +10046,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, "license": "MIT" }, "node_modules/batch": { @@ -10975,6 +10975,48 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/concurrently": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", + "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -11130,7 +11172,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -13426,7 +13467,6 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, "license": "MIT" }, "node_modules/events": { @@ -14799,7 +14839,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, "license": "MIT", "bin": { "he": "bin/he" @@ -14888,7 +14927,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "devOptional": true, "license": "MIT", "dependencies": { "whatwg-encoding": "^2.0.0" @@ -15033,7 +15071,6 @@ "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", @@ -15080,7 +15117,6 @@ "version": "14.1.1", "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", - "dev": true, "license": "MIT", "dependencies": { "basic-auth": "^2.0.1", @@ -17535,7 +17571,6 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, "license": "MIT" }, "node_modules/lodash.clonedeepwith": { @@ -19279,7 +19314,6 @@ "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true, "license": "(WTFPL OR MIT)", "bin": { "opener": "bin/opener-bin.js" @@ -19788,7 +19822,6 @@ "version": "1.0.32", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", - "dev": true, "license": "MIT", "dependencies": { "async": "^2.6.4", @@ -19803,7 +19836,6 @@ "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, "license": "MIT", "dependencies": { "lodash": "^4.17.14" @@ -19813,7 +19845,6 @@ "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -19823,7 +19854,6 @@ "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.6" @@ -21101,7 +21131,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "devOptional": true, "license": "MIT" }, "node_modules/resolve": { @@ -21549,7 +21578,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", - "dev": true, "license": "MIT" }, "node_modules/select-hose": { @@ -23461,7 +23489,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", - "dev": true, "dependencies": { "qs": "^6.4.0" }, @@ -23570,7 +23597,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true, "license": "MIT" }, "node_modules/url-parse": { @@ -24670,7 +24696,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "devOptional": true, "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" @@ -24683,7 +24708,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "devOptional": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" diff --git a/package.json b/package.json index 6e4c993..302af83 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "scripts": { "ng": "ng", "start": "nx serve", + "start:all": "concurrently 'nx serve' 'http-server ../vocab-backend'", "build": "nx build", "watch": "nx build --watch --configuration development" }, @@ -25,6 +26,7 @@ "dotenv": "^16.4.7", "fabric": "^5.4.1", "flowbite": "^2.5.2", + "http-server": "^14.1.1", "reflect-metadata": "^0.1.13", "rxjs": "~7.8.0", "tslib": "^2.3.0", @@ -51,6 +53,7 @@ "@swc/helpers": "~0.5.11", "@types/fabric": "^5.3.9", "@types/node": "~18.16.9", + "concurrently": "^9.1.2", "drizzle-kit": "^0.30.2", "drizzle-orm": "^0.38.4", "nx": "20.3.1", diff --git a/project.json b/project.json index 8f9fc31..343bdb3 100644 --- a/project.json +++ b/project.json @@ -83,7 +83,7 @@ "serve": { "executor": "@angular-devkit/build-angular:dev-server", "options": { - "proxyConfig": "src/proxy.conf.json" + "proxyConfig": "proxy.conf.json" }, "configurations": { "production": { diff --git a/proxy.conf.json b/proxy.conf.json index 9835ea7..a811e84 100644 --- a/proxy.conf.json +++ b/proxy.conf.json @@ -3,5 +3,10 @@ "target": "http://localhost:3000", "secure": false, "changeOrigin": true + }, + "/debug_images": { + "target": "http://localhost:8080", + "secure": false, + "changeOrigin": true } } \ No newline at end of file diff --git a/src/app/deck-list.component.html b/src/app/deck-list.component.html index 46edc9f..5aa9f72 100644 --- a/src/app/deck-list.component.html +++ b/src/app/deck-list.component.html @@ -65,7 +65,7 @@
Processing in progress...
+