Neue Endpunkte
This commit is contained in:
parent
38d2280b88
commit
58d651d981
|
|
@ -2,3 +2,5 @@
|
||||||
__pycache__
|
__pycache__
|
||||||
database.db
|
database.db
|
||||||
debug_images
|
debug_images
|
||||||
|
*.db
|
||||||
|
*.lock
|
||||||
|
|
@ -3,11 +3,16 @@
|
||||||
from flask import Blueprint, request, jsonify
|
from flask import Blueprint, request, jsonify
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
import logging
|
||||||
|
|
||||||
deck_bp = Blueprint('deck_bp', __name__)
|
deck_bp = Blueprint('deck_bp', __name__)
|
||||||
|
|
||||||
DATABASE = 'mydatabase.db'
|
DATABASE = 'mydatabase.db'
|
||||||
|
|
||||||
|
# Logger konfigurieren (angenommen, ocr_server3.py konfiguriert das Logging)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def get_db_connection():
|
def get_db_connection():
|
||||||
conn = sqlite3.connect(DATABASE)
|
conn = sqlite3.connect(DATABASE)
|
||||||
conn.row_factory = sqlite3.Row
|
conn.row_factory = sqlite3.Row
|
||||||
|
|
@ -41,6 +46,48 @@ def init_db():
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def clean_debug_directories():
|
||||||
|
"""
|
||||||
|
Löscht alle Verzeichnisse unter 'debug_images', die keinen Eintrag in der Image-Tabelle haben.
|
||||||
|
"""
|
||||||
|
debug_base_dir = 'debug_images'
|
||||||
|
if not os.path.exists(debug_base_dir):
|
||||||
|
logger.info(f"Debug-Verzeichnis '{debug_base_dir}' existiert nicht. Nichts zu bereinigen.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute('SELECT DISTINCT bildname FROM Image')
|
||||||
|
bildnames = {row['bildname'] for row in cursor.fetchall()}
|
||||||
|
conn.close()
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
logger.error(f"Fehler beim Abrufen der bildname aus der Datenbank: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Durchlaufe alle Verzeichnisse unter 'debug_images'
|
||||||
|
for dir_name in os.listdir(debug_base_dir):
|
||||||
|
dir_path = os.path.join(debug_base_dir, dir_name)
|
||||||
|
if os.path.isdir(dir_path):
|
||||||
|
if dir_name not in bildnames:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(dir_path)
|
||||||
|
logger.info(f"Nicht verwendetes Debug-Verzeichnis gelöscht: {dir_path}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fehler beim Löschen des Verzeichnisses '{dir_path}': {e}")
|
||||||
|
else:
|
||||||
|
logger.debug(f"Debug-Verzeichnis behalten: {dir_path}")
|
||||||
|
|
||||||
|
logger.info("Bereinigung der Debug-Verzeichnisse abgeschlossen.")
|
||||||
|
|
||||||
|
# ------
|
||||||
|
# Endpoints
|
||||||
|
# ------
|
||||||
|
|
||||||
|
# ------
|
||||||
|
# Deck - POST, GET, DELETE
|
||||||
|
# ------
|
||||||
|
|
||||||
@deck_bp.route('/api/decks', methods=['POST'])
|
@deck_bp.route('/api/decks', methods=['POST'])
|
||||||
def create_deck():
|
def create_deck():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
|
|
@ -91,6 +138,7 @@ def get_decks():
|
||||||
conn.close()
|
conn.close()
|
||||||
return jsonify(deck_list)
|
return jsonify(deck_list)
|
||||||
|
|
||||||
|
|
||||||
@deck_bp.route('/api/decks/<deckname>', methods=['DELETE'])
|
@deck_bp.route('/api/decks/<deckname>', methods=['DELETE'])
|
||||||
def delete_deck(deckname):
|
def delete_deck(deckname):
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
|
|
@ -110,36 +158,75 @@ def delete_deck(deckname):
|
||||||
conn.close()
|
conn.close()
|
||||||
return jsonify({'error': 'Deck not found'}), 404
|
return jsonify({'error': 'Deck not found'}), 404
|
||||||
|
|
||||||
@deck_bp.route('/image', methods=['PUT'])
|
# ------
|
||||||
|
# Image - POST, GET, DELETE
|
||||||
|
# ------
|
||||||
|
|
||||||
|
@deck_bp.route('/api/decks/image', methods=['POST'])
|
||||||
def update_image():
|
def update_image():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if not data:
|
if not data:
|
||||||
return jsonify({'error': 'No data provided'}), 400
|
return jsonify({'error': 'No data provided'}), 400
|
||||||
|
|
||||||
required_fields = ['deckid', 'bildname', 'iconindex', 'x1', 'x2', 'y1', 'y2']
|
# Überprüfen, ob die erforderlichen Felder vorhanden sind
|
||||||
|
required_fields = ['deckname', 'image', 'boxes']
|
||||||
if not all(field in data for field in required_fields):
|
if not all(field in data for field in required_fields):
|
||||||
return jsonify({'error': 'Missing fields in data'}), 400
|
return jsonify({'error': 'Missing fields in data'}), 400
|
||||||
|
|
||||||
deckid = data['deckid']
|
deckname = data['deckname']
|
||||||
bildname = data['bildname']
|
bildname = data['image']
|
||||||
iconindex = data['iconindex']
|
boxes = data['boxes']
|
||||||
x1 = data['x1']
|
|
||||||
x2 = data['x2']
|
|
||||||
y1 = data['y1']
|
|
||||||
y2 = data['y2']
|
|
||||||
|
|
||||||
|
# Überprüfen, ob 'boxes' eine Liste ist und mindestens ein Box-Element enthält
|
||||||
|
if not isinstance(boxes, list) or len(boxes) == 0:
|
||||||
|
return jsonify({'error': "'boxes' must be a non-empty list"}), 400
|
||||||
|
|
||||||
|
# Verbindung zur Datenbank herstellen
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('''
|
|
||||||
INSERT INTO Image (deckid, bildname, iconindex, x1, x2, y1, y2)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
||||||
''', (deckid, bildname, iconindex, x1, x2, y1, y2))
|
|
||||||
conn.commit()
|
|
||||||
image_id = cursor.lastrowid
|
|
||||||
conn.close()
|
|
||||||
return jsonify({'status': 'success', 'image_id': image_id}), 201
|
|
||||||
|
|
||||||
@deck_bp.route('/image/<bildname>', methods=['GET'])
|
try:
|
||||||
|
# Deck-ID anhand des Decknamens abrufen
|
||||||
|
cursor.execute('SELECT id FROM Deck WHERE deckname = ?', (deckname,))
|
||||||
|
deck = cursor.fetchone()
|
||||||
|
if not deck:
|
||||||
|
return jsonify({'error': 'Deck not found'}), 404
|
||||||
|
deck_id = deck['id']
|
||||||
|
|
||||||
|
inserted_image_ids = []
|
||||||
|
|
||||||
|
# Durch jede Box iterieren und einen Eintrag in der Image-Tabelle erstellen
|
||||||
|
for index, box in enumerate(boxes):
|
||||||
|
# Überprüfen, ob alle erforderlichen Koordinaten vorhanden sind
|
||||||
|
box_fields = ['x1', 'x2', 'y1', 'y2']
|
||||||
|
if not all(field in box for field in box_fields):
|
||||||
|
return jsonify({'error': 'Missing fields in one of the boxes'}), 400
|
||||||
|
|
||||||
|
x1 = box['x1']
|
||||||
|
x2 = box['x2']
|
||||||
|
y1 = box['y1']
|
||||||
|
y2 = box['y2']
|
||||||
|
|
||||||
|
# Setzen des iconindex auf den aktuellen Index der Box
|
||||||
|
iconindex = index
|
||||||
|
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT INTO Image (deckid, bildname, iconindex, x1, x2, y1, y2)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
''', (deck_id, bildname, iconindex, x1, x2, y1, y2))
|
||||||
|
inserted_image_ids.append(cursor.lastrowid)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
return jsonify({'status': 'success', 'inserted_image_ids': inserted_image_ids}), 201
|
||||||
|
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
conn.rollback()
|
||||||
|
return jsonify({'error': 'Database error', 'details': str(e)}), 500
|
||||||
|
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
@deck_bp.route('/api/decks/image/<bildname>', methods=['GET'])
|
||||||
def get_images_by_bildname(bildname):
|
def get_images_by_bildname(bildname):
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
images = conn.execute('SELECT * FROM Image WHERE bildname = ?', (bildname,)).fetchall()
|
images = conn.execute('SELECT * FROM Image WHERE bildname = ?', (bildname,)).fetchall()
|
||||||
|
|
@ -147,16 +234,64 @@ def get_images_by_bildname(bildname):
|
||||||
image_list = [dict(image) for image in images]
|
image_list = [dict(image) for image in images]
|
||||||
return jsonify(image_list)
|
return jsonify(image_list)
|
||||||
|
|
||||||
@deck_bp.route('/image/<bildname>/<int:iconindex>', methods=['GET'])
|
@deck_bp.route('/api/decks/image/<bildname>', methods=['DELETE'])
|
||||||
def get_image_by_bildname_and_index(bildname, iconindex):
|
def delete_images_by_bildname(bildname):
|
||||||
conn = get_db_connection()
|
"""
|
||||||
image = conn.execute('SELECT * FROM Image WHERE bildname = ? AND iconindex = ?', (bildname, iconindex)).fetchone()
|
Löscht alle Einträge in der Image-Tabelle für den gegebenen bildname.
|
||||||
conn.close()
|
Optional: Löscht das zugehörige Debug-Verzeichnis, wenn keine weiteren Einträge bestehen.
|
||||||
if image is None:
|
"""
|
||||||
return jsonify({'error': 'Image not found'}), 404
|
try:
|
||||||
else:
|
# Sicherheitsmaßnahme: Nur erlaubte Zeichen im bildname
|
||||||
return jsonify(dict(image)), 200
|
if not all(c.isalnum() or c in ('_', '-') for c in bildname):
|
||||||
|
logger.warning(f"Ungültiger bildname angefordert: {bildname}")
|
||||||
|
return jsonify({'error': 'Invalid image name'}), 400
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Überprüfen, ob es Einträge mit dem bildname gibt
|
||||||
|
cursor.execute('SELECT COUNT(*) as count FROM Image WHERE bildname = ?', (bildname,))
|
||||||
|
result = cursor.fetchone()
|
||||||
|
count = result['count'] if result else 0
|
||||||
|
|
||||||
|
if count == 0:
|
||||||
|
conn.close()
|
||||||
|
return jsonify({'error': 'No entries found for the given image name'}), 404
|
||||||
|
|
||||||
|
# Löschen der Einträge
|
||||||
|
cursor.execute('DELETE FROM Image WHERE bildname = ?', (bildname,))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Optional: Löschen des Debug-Verzeichnisses, wenn keine weiteren Einträge bestehen
|
||||||
|
# Überprüfen, ob das Verzeichnis existiert
|
||||||
|
debug_dir = os.path.join('debug_images', bildname)
|
||||||
|
if os.path.exists(debug_dir):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(debug_dir)
|
||||||
|
logger.info(f"Debug-Verzeichnis gelöscht: {debug_dir}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fehler beim Löschen des Debug-Verzeichnisses '{debug_dir}': {e}")
|
||||||
|
# Sie können entscheiden, ob Sie einen Fehler zurückgeben oder nicht
|
||||||
|
# Hier geben wir eine Warnung zurück, aber setzen die Anfrage als erfolgreich fort
|
||||||
|
return jsonify({
|
||||||
|
'status': 'success',
|
||||||
|
'message': 'Database entries deleted, but failed to delete debug directory.',
|
||||||
|
'details': str(e)
|
||||||
|
}), 200
|
||||||
|
|
||||||
|
return jsonify({'status': 'success', 'message': f'All entries for image "{bildname}" have been deleted.'}), 200
|
||||||
|
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
logger.error(f"Fehler beim Löschen der Image-Einträge für '{bildname}': {e}")
|
||||||
|
return jsonify({'error': 'Database error', 'details': str(e)}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Unerwarteter Fehler beim Löschen der Image-Einträge für '{bildname}': {e}")
|
||||||
|
return jsonify({'error': 'Failed to delete image entries', 'details': str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
# Sicherstellen, dass die Datenbank existiert
|
# Sicherstellen, dass die Datenbank existiert
|
||||||
if not os.path.exists(DATABASE):
|
if not os.path.exists(DATABASE):
|
||||||
init_db()
|
init_db()
|
||||||
|
clean_debug_directories()
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- database: ./mydatabase.db
|
||||||
|
|
||||||
|
SELECT distinct bildname FROM Image;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify, send_file
|
||||||
from paddleocr import PaddleOCR
|
from paddleocr import PaddleOCR
|
||||||
import base64
|
import base64
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
@ -202,5 +202,32 @@ def ocr_endpoint():
|
||||||
'debug_dir': debug_dir if 'debug_dir' in locals() else None
|
'debug_dir': debug_dir if 'debug_dir' in locals() else None
|
||||||
}), 500
|
}), 500
|
||||||
|
|
||||||
|
@app.route('/api/debug_image/<name>', methods=['GET'])
|
||||||
|
def get_debug_image(name):
|
||||||
|
"""
|
||||||
|
Gibt das Originalbild unter 'debug_images/[name]/original.png' direkt als image/png zurück.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Sicherheitsmaßnahme: Nur erlaubte Zeichen im Namen
|
||||||
|
if not all(c.isalnum() or c in ('_', '-') for c in name):
|
||||||
|
logger.warning(f"Ungültiger Bildname angefordert: {name}")
|
||||||
|
return jsonify({'error': 'Invalid image name'}), 400
|
||||||
|
|
||||||
|
image_path = os.path.join('debug_images', name, 'original.png')
|
||||||
|
if not os.path.isfile(image_path):
|
||||||
|
logger.warning(f"Bild nicht gefunden: {image_path}")
|
||||||
|
return jsonify({'error': 'Image not found'}), 404
|
||||||
|
|
||||||
|
return send_file(
|
||||||
|
image_path,
|
||||||
|
mimetype='image/png',
|
||||||
|
as_attachment=False
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fehler beim Abrufen des Bildes '{name}': {str(e)}")
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
return jsonify({'error': 'Failed to retrieve image'}), 500
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "vocab-backend"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["Andreas Knuth <andreas.knuth@gmail.com>"]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.10"
|
||||||
|
flask = "^2.2.3"
|
||||||
|
paddleocr = "^2.9.1"
|
||||||
|
pillow = "^9.4.0"
|
||||||
|
numpy = "^1.23.5" # Korrigiere dies auf eine 1.x-Version
|
||||||
|
opencv-python = "^4.6.0.66"
|
||||||
|
paddlepaddle = "^2.6.2"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
||||||
Loading…
Reference in New Issue