diff --git a/app.py b/app.py
index 8c61f0c..51f9969 100644
--- a/app.py
+++ b/app.py
@@ -1,9 +1,10 @@
import logging
-from flask import Flask
+from flask import Flask, request
+from flask_cors import cross_origin
import config
-from dto.requests import GameStartRequestDTO
+from dto.requests import GameStartRequestDTO, GameDecisionRequestDTO
from services.julius_baer_api_client import JuliusBaerApiClient
app = Flask(__name__)
@@ -12,6 +13,7 @@ jb_client = JuliusBaerApiClient()
@app.route('/new-game', methods=['POST'])
+@cross_origin() # allow all origins all methods
def new_game():
game_start_request = GameStartRequestDTO(player_name=config.API_TEAM)
res = jb_client.start_game(game_start_request)
@@ -19,5 +21,18 @@ def new_game():
return res.model_dump_json()
+@app.route('/next', methods=['POST'])
+def next_client():
+ body = request.get_json()
+
+ decision = body.get("decision")
+ client_id = body.get("client_id")
+ session_id = body.get("session_id")
+
+ make_decision_request = GameDecisionRequestDTO(decision=decision, client_id=client_id, session_id=session_id)
+ res = jb_client.send_decision(make_decision_request)
+
+ return res.model_dump_json()
+
if __name__ == '__main__':
app.run()
diff --git a/frontend/src/index.html b/frontend/src/index.html
index f7f2345..c61aa0c 100644
--- a/frontend/src/index.html
+++ b/frontend/src/index.html
@@ -6,7 +6,26 @@
PDF Viewer
-
+
+
+
+
+ Loading game data...
+
+
+
+
+
+
+
+
+
+
Game Ready!
+
Session ID:
+
First Client ID:
+
+
+
Hello, Bootstrap and Vite!
diff --git a/frontend/src/js/main.js b/frontend/src/js/main.js
index f20c7d3..f49da2e 100644
--- a/frontend/src/js/main.js
+++ b/frontend/src/js/main.js
@@ -7,6 +7,64 @@ import Alpine from 'alpinejs'
window.Alpine = Alpine
+// Define an Alpine component to manage the game state
+Alpine.data('gameManager', () => ({
+ // --- Component State ---
+ isLoading: false,
+ error: null,
+ gameData: null,
+
+ init() {
+ console.log('Game manager initializing...');
+ this.startNewGame();
+ },
+
+ startNewGame() {
+ this.isLoading = true;
+ this.error = null;
+ this.gameData = null;
+
+ // Use the browser's fetch API
+ fetch('http://127.0.0.1:5000/new-game', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ })
+ .then(response => {
+ // Check if the request was successful (status code 2xx)
+ if (!response.ok) {
+ // If not okay, throw an error to be caught by .catch()
+ // Try to get error details from response body if possible
+ return response.json().then(errData => {
+ throw new Error(errData.detail || `HTTP error! status: ${response.status}`);
+ }).catch(() => {
+ // Fallback if response is not JSON or other error
+ throw new Error(`HTTP error! status: ${response.status}`);
+ });
+ }
+ // If okay, parse the JSON response body
+ return response.json();
+ })
+ .then(data => {
+ // Success! Store the received game data
+ console.log('New game data received:', data);
+ this.gameData = data; // e.g., { message, session_id, client_id, ... }
+ })
+ .catch(error => {
+ // Handle any errors during fetch or processing
+ console.error('Error starting new game:', error);
+ this.error = error.message || 'Failed to start game. Check console/backend.';
+ })
+ .finally(() => {
+ // This runs regardless of success or failure
+ this.isLoading = false; // Turn off loading indicator
+ });
+ }
+
+ // submitDecision(decision) { ... }
+}));
+
Alpine.data('pdfViewer', () => ({
pdfUrl: null,
diff --git a/requirements.txt b/requirements.txt
index 1d44aa1..df31072 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -40,4 +40,6 @@ Flask==3.1.0
annotated-types==0.7.0
blinker==1.9.0
langchain-google-genai==2.1.2
-numpy==2.2.4
\ No newline at end of file
+numpy==2.2.4
+pymupdf == 1.25.5
+flask-cors==5.0.1
diff --git a/resources/decision_log2.csv b/resources/decision_log2.csv
index e3a892e..f817b7d 100644
--- a/resources/decision_log2.csv
+++ b/resources/decision_log2.csv
@@ -26,3 +26,10 @@ ad6b6980-7b2e-4af9-bda0-2ec004574211,Accept
ac62e33d-6645-4360-8e14-21bfb0b6902a,Accept
d5789f9c-a0f4-4663-9c6e-0d416bbbffb8,Accept
25a429d6-bd8a-45d2-af1d-a0b8e5ec2e72,Accept
+e592968f-4970-4aad-82d5-9f9383e3ae57,Accept
+ef70356d-5014-498e-9897-643b6bc88dab,Accept
+87db27e8-e1ff-4915-8dd2-2dc4afb570a4,Accept
+161cffea-a125-4496-a0fc-17d21e2ae512,Accept
+aaa05711-5e4b-455e-9971-fdba386441e9,Accept
+3709c954-6c2e-42a5-90f7-8b73c374943f,Accept
+f3054c1b-ad4a-4cad-be7b-03cb192f5c45,Accept
diff --git a/tests/dummy.py b/tests/dummy.py
index efd5cb0..87c43f8 100644
--- a/tests/dummy.py
+++ b/tests/dummy.py
@@ -113,8 +113,8 @@ def dummy_data() -> ExtractedData:
def dummy_client_data() -> dict[str, Any]:
# TODO make generic
- resp_path = f"{config.GAME_FILES_DIR}/65e6ec83-88b1-4d1f-8560-a1418803348b/000000_decision_accept_active/000000_response.json"
+ resp_path = f"{config.GAME_FILES_DIR}/fc3b1f5a-296d-4cd0-a560-cfa5a6f8d302/000000_decision_accept_active/000000_response.json"
out = {}
with open(resp_path, "r") as file:
- out = json.loads(str(json.loads(file.read())))
+ out = json.loads(file.read())["client_data"]
return out
\ No newline at end of file
diff --git a/tests/test_parser.py b/tests/test_parser.py
new file mode 100644
index 0000000..db98168
--- /dev/null
+++ b/tests/test_parser.py
@@ -0,0 +1,7 @@
+from tests.dummy import dummy_client_data
+from utils.parsers.passport_parser import process_passport
+
+
+def test_passport_parser() -> None:
+ client_data = dummy_client_data()
+ process_passport(client_data.get("passport"))
\ No newline at end of file
diff --git a/utils/parsers/account_parser.py b/utils/parsers/account_parser.py
index 6d293c9..75fd1ea 100644
--- a/utils/parsers/account_parser.py
+++ b/utils/parsers/account_parser.py
@@ -1,22 +1,38 @@
import base64
-from pdf2image import convert_from_bytes
-import pytesseract
-
+import pymupdf
def process_account(account_b64: str) -> str:
"""
Traite l'account :
- Décodage du PDF encodé en base64.
- - Conversion de chaque page du PDF en image.
- - Application de l'OCR sur chaque image pour extraire le texte.
+ - Extraction du texte et des champs de formulaire directement depuis le PDF.
:param account_b64: Chaîne base64 représentant le PDF.
- :return: Texte extrait de chaque page du PDF.
+ :return: Texte extrait de chaque page du PDF, incluant les champs du formulaire.
"""
+ # Décodage du PDF en base64
pdf_bytes = base64.b64decode(account_b64)
- images = convert_from_bytes(pdf_bytes)
- pages_text = []
- for i, image in enumerate(images):
- text = pytesseract.image_to_string(image, lang="eng")
- pages_text.append(f"--- Page {i + 1} ---\n{text}")
- return "\n".join(pages_text)
\ No newline at end of file
+
+ # Ouverture du PDF avec PyMuPDF
+ pdf_document = pymupdf.open(stream=pdf_bytes, filetype="pdf")
+
+ # Traitement de chaque page
+ for i in range(len(pdf_document)):
+ page = pdf_document[i]
+
+ # Extraction des champs de formulaire
+ fields = page.widgets()
+ form_fields_text = []
+
+ for field in fields:
+ field_name = field.field_name
+ field_value = field.field_value
+ form_fields_text.append(f"Field: {field_name}, Value: {field_value}")
+
+ combined_text = ""
+
+ if form_fields_text:
+ combined_text += "\n\nForm Fields:\n" + "\n".join(form_fields_text)
+
+ pdf_document.close()
+ return "\n".join(combined_text)
\ No newline at end of file
diff --git a/utils/parsers/passport_parser.py b/utils/parsers/passport_parser.py
index 10dd221..7975370 100644
--- a/utils/parsers/passport_parser.py
+++ b/utils/parsers/passport_parser.py
@@ -1,8 +1,10 @@
import base64
import io
+from tempfile import NamedTemporaryFile
from PIL import Image
import pytesseract
-
+from passporteye import read_mrz
+import json
def process_passport(passport_b64: str) -> str:
"""
@@ -14,6 +16,12 @@ def process_passport(passport_b64: str) -> str:
:return: Texte extrait de l'image.
"""
image_bytes = base64.b64decode(passport_b64)
- image = Image.open(io.BytesIO(image_bytes))
- text = pytesseract.image_to_string(image, lang='eng')
+ # image = Image.open(io.BytesIO(image_bytes))
+ # text = pytesseract.image_to_string(image, lang='eng')
+ with NamedTemporaryFile(mode="wb") as tmp_img:
+ tmp_img.write(image_bytes)
+ with open(tmp_img.name, "rb") as read_img:
+ text = read_mrz(read_img)
+ # text = json.dumps(text)
+ # TODO CONTINUE
return text
\ No newline at end of file