Compare commits
7 Commits
b17afbb5cd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
e4db258bc5
|
|||
|
449adc60e0
|
|||
|
d68dc8411f
|
|||
|
60f776c56d
|
|||
|
7228dc4ec6
|
|||
|
e4989dcc8d
|
|||
|
3fdbfcf20e
|
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
# Use Python 3.13 slim image as base
|
# Use Python 3.13 slim image as base
|
||||||
FROM python:3.13-slim AS builder
|
FROM python:3.14-slim AS builder
|
||||||
|
|
||||||
# Set working directory
|
# Set working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -17,7 +17,7 @@ RUN --mount=type=cache,id=pip,target=/root/.cache/pip \
|
|||||||
--target=/app/site-packages \
|
--target=/app/site-packages \
|
||||||
-r requirements.txt
|
-r requirements.txt
|
||||||
|
|
||||||
FROM python:3.13-slim
|
FROM python:3.14-slim
|
||||||
|
|
||||||
COPY --from=builder /app/site-packages /app/site-packages
|
COPY --from=builder /app/site-packages /app/site-packages
|
||||||
|
|
||||||
|
|||||||
+204
-11
@@ -5,17 +5,42 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Générateur d'Exercices de Mathématiques</title>
|
<title>Générateur d'Exercices de Mathématiques</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
|
:root {
|
||||||
|
--bs-body-bg: #ffffff;
|
||||||
|
--bs-body-color: #212529;
|
||||||
|
--bs-border-color: #dee2e6;
|
||||||
|
--bs-secondary-bg: #f8f9fa;
|
||||||
|
--bs-tertiary-bg: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] {
|
||||||
|
--bs-body-bg: #121212;
|
||||||
|
--bs-body-color: #e9ecef;
|
||||||
|
--bs-border-color: #495057;
|
||||||
|
--bs-secondary-bg: #212529;
|
||||||
|
--bs-tertiary-bg: #343a40;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bs-body-bg);
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
transition: background-color 0.3s ease, color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||||
transition: 0.3s;
|
transition: 0.3s;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
background-color: var(--bs-tertiary-bg);
|
||||||
|
border-color: var(--bs-border-color);
|
||||||
}
|
}
|
||||||
.card:hover {
|
.card:hover {
|
||||||
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
|
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
.exercise-result {
|
.exercise-result {
|
||||||
background-color: #f8f9fa;
|
background-color: var(--bs-secondary-bg);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
@@ -25,9 +50,81 @@
|
|||||||
height: 3rem;
|
height: 3rem;
|
||||||
margin-right: 0.75rem;
|
margin-right: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark-mode-toggle {
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
z-index: 1000;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: none;
|
||||||
|
background-color: var(--bs-tertiary-bg);
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark-mode-toggle:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .bg-light {
|
||||||
|
background-color: var(--bs-secondary-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .text-muted {
|
||||||
|
color: var(--bs-body-color) !important;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .table {
|
||||||
|
--bs-table-bg: var(--bs-tertiary-bg);
|
||||||
|
--bs-table-striped-bg: var(--bs-secondary-bg);
|
||||||
|
--bs-table-hover-bg: var(--bs-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .alert {
|
||||||
|
border-color: var(--bs-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .form-control,
|
||||||
|
[data-bs-theme="dark"] .form-select {
|
||||||
|
background-color: var(--bs-tertiary-bg);
|
||||||
|
border-color: var(--bs-border-color);
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .form-control:focus,
|
||||||
|
[data-bs-theme="dark"] .form-select:focus {
|
||||||
|
background-color: var(--bs-tertiary-bg);
|
||||||
|
border-color: var(--bs-primary);
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .form-check-input {
|
||||||
|
background-color: var(--bs-tertiary-bg);
|
||||||
|
border-color: var(--bs-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] .form-check-input:checked {
|
||||||
|
background-color: var(--bs-primary);
|
||||||
|
border-color: var(--bs-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-all {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Dark Mode Toggle Button -->
|
||||||
|
<button class="dark-mode-toggle" id="darkModeToggle" title="Basculer le mode sombre" aria-label="Basculer le mode sombre">
|
||||||
|
<i class="bi bi-moon-fill" id="darkModeIcon"></i>
|
||||||
|
</button>
|
||||||
<div class="container mt-5 mb-5">
|
<div class="container mt-5 mb-5">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
@@ -61,9 +158,20 @@
|
|||||||
<div class="form-text">Nombre total d'exercices à générer (entre 1 et 100)</div>
|
<div class="form-text">Nombre total d'exercices à générer (entre 1 et 100)</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
<div class="mb-3">
|
||||||
<input type="checkbox" class="form-check-input" id="multiplicationOnly">
|
<label class="form-label">Types d'exercices</label>
|
||||||
<label class="form-check-label" for="multiplicationOnly">Générer uniquement des multiplications</label>
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="exerciseType" id="multiplicationOnly" value="multiplication" checked>
|
||||||
|
<label class="form-check-label" for="multiplicationOnly">
|
||||||
|
Multiplications uniquement
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="radio" name="exerciseType" id="multiplicationAndDivision" value="both">
|
||||||
|
<label class="form-check-label" for="multiplicationAndDivision">
|
||||||
|
Multiplications ET divisions
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -240,7 +348,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="bg-light text-center text-muted py-4 mt-5">
|
<footer class="bg-light text-center text-muted py-4 mt-5 transition-all">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>Générateur d'Exercices de Mathématiques © 2025</p>
|
<p>Générateur d'Exercices de Mathématiques © 2025</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -248,6 +356,72 @@
|
|||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
// Dark Mode Theme Management
|
||||||
|
class ThemeManager {
|
||||||
|
constructor() {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// Load saved theme or detect system preference
|
||||||
|
const savedTheme = localStorage.getItem('theme');
|
||||||
|
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||||
|
const theme = savedTheme || systemTheme;
|
||||||
|
|
||||||
|
this.setTheme(theme);
|
||||||
|
|
||||||
|
// Listen for system theme changes
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||||
|
if (!localStorage.getItem('theme')) {
|
||||||
|
this.setTheme(e.matches ? 'dark' : 'light');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup toggle button
|
||||||
|
this.setupToggleButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTheme(theme) {
|
||||||
|
document.documentElement.setAttribute('data-bs-theme', theme);
|
||||||
|
localStorage.setItem('theme', theme);
|
||||||
|
this.updateToggleIcon(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTheme() {
|
||||||
|
const currentTheme = document.documentElement.getAttribute('data-bs-theme');
|
||||||
|
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||||
|
this.setTheme(newTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateToggleIcon(theme) {
|
||||||
|
const icon = document.getElementById('darkModeIcon');
|
||||||
|
if (theme === 'dark') {
|
||||||
|
icon.className = 'bi bi-sun-fill';
|
||||||
|
} else {
|
||||||
|
icon.className = 'bi bi-moon-fill';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupToggleButton() {
|
||||||
|
const toggleButton = document.getElementById('darkModeToggle');
|
||||||
|
toggleButton.addEventListener('click', () => {
|
||||||
|
this.toggleTheme();
|
||||||
|
this.animateToggle();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
animateToggle() {
|
||||||
|
const button = document.getElementById('darkModeToggle');
|
||||||
|
button.style.transform = 'scale(0.9)';
|
||||||
|
setTimeout(() => {
|
||||||
|
button.style.transform = '';
|
||||||
|
}, 150);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize theme manager
|
||||||
|
const themeManager = new ThemeManager();
|
||||||
|
|
||||||
// Current page for pagination
|
// Current page for pagination
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
@@ -258,7 +432,7 @@
|
|||||||
minTable: document.getElementById('minTable').value,
|
minTable: document.getElementById('minTable').value,
|
||||||
maxTable: document.getElementById('maxTable').value,
|
maxTable: document.getElementById('maxTable').value,
|
||||||
numExercises: document.getElementById('numExercises').value,
|
numExercises: document.getElementById('numExercises').value,
|
||||||
multiplicationOnly: document.getElementById('multiplicationOnly').checked,
|
exerciseType: document.querySelector('input[name="exerciseType"]:checked').value,
|
||||||
maxFirstOperand: document.getElementById('maxFirstOperand').value
|
maxFirstOperand: document.getElementById('maxFirstOperand').value
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -279,7 +453,18 @@
|
|||||||
document.getElementById('minTable').value = exerciseValues.minTable || 1;
|
document.getElementById('minTable').value = exerciseValues.minTable || 1;
|
||||||
document.getElementById('maxTable').value = exerciseValues.maxTable || 10;
|
document.getElementById('maxTable').value = exerciseValues.maxTable || 10;
|
||||||
document.getElementById('numExercises').value = exerciseValues.numExercises || 15;
|
document.getElementById('numExercises').value = exerciseValues.numExercises || 15;
|
||||||
document.getElementById('multiplicationOnly').checked = exerciseValues.multiplicationOnly || false;
|
|
||||||
|
// Restore radio button selection
|
||||||
|
if (exerciseValues.exerciseType) {
|
||||||
|
const radio = document.querySelector(`input[name="exerciseType"][value="${exerciseValues.exerciseType}"]`);
|
||||||
|
if (radio) {
|
||||||
|
radio.checked = true;
|
||||||
|
}
|
||||||
|
} else if (exerciseValues.multiplicationOnly !== undefined) {
|
||||||
|
// Handle legacy storage format
|
||||||
|
document.getElementById('multiplicationOnly').checked = exerciseValues.multiplicationOnly;
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('maxFirstOperand').value = exerciseValues.maxFirstOperand || 10;
|
document.getElementById('maxFirstOperand').value = exerciseValues.maxFirstOperand || 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,18 +648,25 @@
|
|||||||
|
|
||||||
// Load PDF list on page load
|
// Load PDF list on page load
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
restoreFormValues();
|
// Ensure theme is initialized first
|
||||||
loadPdfList(currentPage);
|
setTimeout(() => {
|
||||||
|
restoreFormValues();
|
||||||
|
loadPdfList(currentPage);
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add event listeners to save form values on change
|
// Add event listeners to save form values on change
|
||||||
document.getElementById('minTable').addEventListener('change', saveFormValues);
|
document.getElementById('minTable').addEventListener('change', saveFormValues);
|
||||||
document.getElementById('maxTable').addEventListener('change', saveFormValues);
|
document.getElementById('maxTable').addEventListener('change', saveFormValues);
|
||||||
document.getElementById('numExercises').addEventListener('change', saveFormValues);
|
document.getElementById('numExercises').addEventListener('change', saveFormValues);
|
||||||
document.getElementById('multiplicationOnly').addEventListener('change', saveFormValues);
|
|
||||||
document.getElementById('maxFirstOperand').addEventListener('change', saveFormValues);
|
document.getElementById('maxFirstOperand').addEventListener('change', saveFormValues);
|
||||||
document.getElementById('numOperationExercises').addEventListener('change', saveFormValues);
|
document.getElementById('numOperationExercises').addEventListener('change', saveFormValues);
|
||||||
|
|
||||||
|
// Add event listeners for radio buttons
|
||||||
|
document.querySelectorAll('input[name="exerciseType"]').forEach(radio => {
|
||||||
|
radio.addEventListener('change', saveFormValues);
|
||||||
|
});
|
||||||
|
|
||||||
// Event listener for select all button
|
// Event listener for select all button
|
||||||
document.getElementById('selectAllBtn').addEventListener('click', function() {
|
document.getElementById('selectAllBtn').addEventListener('click', function() {
|
||||||
document.querySelectorAll('.file-checkbox').forEach(checkbox => {
|
document.querySelectorAll('.file-checkbox').forEach(checkbox => {
|
||||||
@@ -577,7 +769,8 @@
|
|||||||
const minTable = parseInt(document.getElementById('minTable').value);
|
const minTable = parseInt(document.getElementById('minTable').value);
|
||||||
const maxTable = parseInt(document.getElementById('maxTable').value);
|
const maxTable = parseInt(document.getElementById('maxTable').value);
|
||||||
const numExercises = parseInt(document.getElementById('numExercises').value);
|
const numExercises = parseInt(document.getElementById('numExercises').value);
|
||||||
const multiplicationOnly = document.getElementById('multiplicationOnly').checked;
|
const exerciseType = document.querySelector('input[name="exerciseType"]:checked').value;
|
||||||
|
const multiplicationOnly = (exerciseType === 'multiplication');
|
||||||
const maxFirstOperand = parseInt(document.getElementById('maxFirstOperand').value);
|
const maxFirstOperand = parseInt(document.getElementById('maxFirstOperand').value);
|
||||||
|
|
||||||
const generateBtn = document.getElementById('generateBtn');
|
const generateBtn = document.getElementById('generateBtn');
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ spec:
|
|||||||
httpGet:
|
httpGet:
|
||||||
path: /health
|
path: /health
|
||||||
port: 8000
|
port: 8000
|
||||||
initialDelaySeconds: 5
|
initialDelaySeconds: 2
|
||||||
periodSeconds: 10
|
periodSeconds: 3
|
||||||
timeoutSeconds: 3
|
timeoutSeconds: 3
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
# Environment variables from ConfigMap
|
# Environment variables from ConfigMap
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
app: keda-add-ons-http-interceptor-proxy
|
||||||
|
name: keda-add-ons-http-interceptor-proxy
|
||||||
|
spec:
|
||||||
|
externalName: keda-add-ons-http-interceptor-proxy.keda
|
||||||
|
selector:
|
||||||
|
app: keda-add-ons-http-interceptor-proxy
|
||||||
|
type: ExternalName
|
||||||
|
status:
|
||||||
|
loadBalancer: {}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
kind: HTTPScaledObject
|
||||||
|
apiVersion: http.keda.sh/v1alpha1
|
||||||
|
metadata:
|
||||||
|
name: math-exercises
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- "math-tables.cl1.parano.ch"
|
||||||
|
pathPrefixes:
|
||||||
|
- /
|
||||||
|
scaleTargetRef:
|
||||||
|
name: math-exercises-app
|
||||||
|
kind: Deployment
|
||||||
|
apiVersion: apps/v1
|
||||||
|
service: math-exercises-service
|
||||||
|
portName: http
|
||||||
|
replicas:
|
||||||
|
min: 0
|
||||||
|
max: 3
|
||||||
|
scaledownPeriod: 60
|
||||||
|
scalingMetric:
|
||||||
|
requestRate:
|
||||||
|
granularity: 1s
|
||||||
|
targetValue: 100
|
||||||
|
window: 1m
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
namespace: math-tables
|
||||||
|
resources:
|
||||||
|
- ../production
|
||||||
|
- external-service.yaml
|
||||||
|
- http-scaled-object.yaml
|
||||||
|
patches:
|
||||||
|
- patch: |
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"op": "remove",
|
||||||
|
"path": "/spec/replicas"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: math-exercises-app
|
||||||
|
- path: remove-pdb.yaml
|
||||||
|
- patch: |
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/spec/rules/0/http/paths/0/backend/service/port/number",
|
||||||
|
"value": 8080
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/spec/rules/0/http/paths/0/backend/service/name",
|
||||||
|
"value": "keda-add-ons-http-interceptor-proxy"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
target:
|
||||||
|
group: networking.k8s.io
|
||||||
|
version: v1
|
||||||
|
kind: Ingress
|
||||||
|
name: math-exercises-ingress
|
||||||
|
- patch: |
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/spec/internalTrafficPolicy",
|
||||||
|
"value": "Cluster"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
target:
|
||||||
|
version: v1
|
||||||
|
kind: Service
|
||||||
|
name: math-exercises-service
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: math-exercises-pdb
|
||||||
|
$patch: delete
|
||||||
@@ -13,7 +13,7 @@ resources:
|
|||||||
images:
|
images:
|
||||||
- name: math-exercises
|
- name: math-exercises
|
||||||
newName: harbor.cl1.parano.ch/library/math-exercice
|
newName: harbor.cl1.parano.ch/library/math-exercice
|
||||||
newTag: 1.1.0
|
newTag: 1.4.0
|
||||||
|
|
||||||
# Production-specific labels
|
# Production-specific labels
|
||||||
|
|
||||||
|
|||||||
+24
-24
@@ -1,32 +1,32 @@
|
|||||||
|
annotated-doc==0.0.4
|
||||||
annotated-types==0.7.0
|
annotated-types==0.7.0
|
||||||
anyio==4.10.0
|
anyio==4.12.0
|
||||||
boto3==1.26.160
|
boto3==1.42.6
|
||||||
boto3-stubs==1.40.23
|
boto3-stubs==1.42.6
|
||||||
botocore==1.29.165
|
botocore==1.42.6
|
||||||
botocore-stubs==1.40.23
|
botocore-stubs==1.42.6
|
||||||
click==8.2.1
|
click==8.3.1
|
||||||
defusedxml==0.7.1
|
defusedxml==0.7.1
|
||||||
fastapi==0.116.1
|
fastapi==0.124.0
|
||||||
fonttools==4.59.2
|
fonttools==4.61.0
|
||||||
fpdf2==2.8.4
|
fpdf2==2.8.5
|
||||||
h11==0.16.0
|
h11==0.16.0
|
||||||
idna==3.10
|
idna==3.11
|
||||||
Jinja2==3.1.4
|
Jinja2==3.1.6
|
||||||
jmespath==1.0.1
|
jmespath==1.0.1
|
||||||
MarkupSafe==3.0.2
|
MarkupSafe==3.0.3
|
||||||
pillow==11.3.0
|
pillow==12.0.0
|
||||||
pydantic==2.11.7
|
pydantic==2.12.5
|
||||||
pydantic_core==2.33.2
|
pydantic_core==2.41.5
|
||||||
python-dateutil==2.9.0.post0
|
python-dateutil==2.9.0.post0
|
||||||
python-multipart==0.0.9
|
python-multipart==0.0.20
|
||||||
s3transfer==0.6.2
|
s3transfer==0.16.0
|
||||||
six==1.17.0
|
six==1.17.0
|
||||||
sniffio==1.3.1
|
sniffio==1.3.1
|
||||||
starlette==0.47.3
|
starlette==0.50.0
|
||||||
types-awscrt==0.27.6
|
types-awscrt==0.29.2
|
||||||
types-fpdf2==2.8.4.20250822
|
types-s3transfer==0.16.0
|
||||||
types-s3transfer==0.13.1
|
typing-inspection==0.4.2
|
||||||
typing-inspection==0.4.1
|
|
||||||
typing_extensions==4.15.0
|
typing_extensions==4.15.0
|
||||||
urllib3==1.26.20
|
urllib3==2.6.1
|
||||||
uvicorn==0.30.6
|
uvicorn==0.38.0
|
||||||
|
|||||||
Reference in New Issue
Block a user