OUAREDAEK commited on
Commit
e509a2b
·
verified ·
1 Parent(s): 91f69cf

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +215 -0
app.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import sys
3
+ import os
4
+ import json
5
+ from datetime import datetime
6
+
7
+ # --------------------------------------------------
8
+ # 🔧 Auto-install Flask if missing
9
+ # --------------------------------------------------
10
+ def install_if_missing(package):
11
+ try:
12
+ __import__(package)
13
+ except ImportError:
14
+ print(f"⚡ Installing missing package: {package}")
15
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package])
16
+
17
+ install_if_missing("flask")
18
+
19
+ # --------------------------------------------------
20
+ # 📦 Imports
21
+ # --------------------------------------------------
22
+ from flask import Flask, render_template, request, jsonify, send_from_directory
23
+
24
+ # --------------------------------------------------
25
+ # ⚙️ CONFIGURATION GLOBALE
26
+ # --------------------------------------------------
27
+ PORT = int(os.environ.get("PORT", 7860))
28
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
29
+
30
+ CROSS_READING_DIR = os.path.join(BASE_DIR, "cross_reading")
31
+ TEMPLATES_DIR = os.path.join(BASE_DIR, "templates")
32
+ STATIC_DIR = os.path.join(BASE_DIR, "static")
33
+ DATA_DIR = os.path.join(BASE_DIR, "data")
34
+
35
+ SCENARIOS_FILE = os.path.join(CROSS_READING_DIR, "scenarios.json")
36
+ SCENARIOS_LIST_FILE = os.path.join(CROSS_READING_DIR, "scenarios_list.json")
37
+ STATS_FILE = os.path.join(CROSS_READING_DIR, "trust_stats.json")
38
+ REVIEW_FILE = os.path.join(CROSS_READING_DIR, "review.json")
39
+ CALIBRATION_FILE = os.path.join(CROSS_READING_DIR, "calibration-trust.json")
40
+
41
+ CROSS_HTML = "cross_readers.html"
42
+ CROSS_JS = "cross_readers.js"
43
+
44
+ app = Flask(
45
+ __name__,
46
+ template_folder=TEMPLATES_DIR,
47
+ static_folder=STATIC_DIR
48
+ )
49
+
50
+ # --------------------------------------------------
51
+ # 🌐 ROUTES UI
52
+ # --------------------------------------------------
53
+ @app.route("/")
54
+ def index():
55
+ return render_template("index.html")
56
+
57
+ @app.route("/cross_readers.html")
58
+ @app.route("/cross_reading/cross_readers.html")
59
+ def cross_readers():
60
+ if os.path.exists(os.path.join(CROSS_READING_DIR, CROSS_HTML)):
61
+ return send_from_directory(CROSS_READING_DIR, CROSS_HTML)
62
+ return "cross_readers.html introuvable", 404
63
+
64
+ @app.route("/cross_reading/cross_readers.js")
65
+ def cross_readers_js():
66
+ return send_from_directory(CROSS_READING_DIR, CROSS_JS)
67
+
68
+ # --------------------------------------------------
69
+ # 📘 API – SCÉNARIOS
70
+ # --------------------------------------------------
71
+ @app.route("/api/scenarios")
72
+ def get_scenarios():
73
+ with open(SCENARIOS_FILE, "r", encoding="utf-8") as f:
74
+ return jsonify(json.load(f))
75
+
76
+ @app.route("/api/scenarios_list")
77
+ def get_scenarios_list():
78
+ with open(SCENARIOS_LIST_FILE, "r", encoding="utf-8") as f:
79
+ return jsonify(json.load(f))
80
+
81
+ # --------------------------------------------------
82
+ # 🔧 API – TRUST CALIBRATION
83
+ # --------------------------------------------------
84
+ @app.route("/api/trust/calibration")
85
+ def get_trust_calibration():
86
+ with open(CALIBRATION_FILE, "r", encoding="utf-8") as f:
87
+ return jsonify(json.load(f))
88
+
89
+ @app.route("/api/trust/calibration", methods=["POST"])
90
+ def save_trust_calibration():
91
+ data = request.json
92
+ with open(CALIBRATION_FILE, "w", encoding="utf-8") as f:
93
+ json.dump(data, f, indent=2, ensure_ascii=False)
94
+ return jsonify({"status": "ok"})
95
+
96
+ # --------------------------------------------------
97
+ # 💾 API – TRUST (quantitatif)
98
+ # --------------------------------------------------
99
+ @app.route("/save_trust", methods=["POST"])
100
+ def save_trust():
101
+ data = request.json
102
+
103
+ record = {
104
+ "scenario_id": data.get("scenario_id"),
105
+ "trust_metrics": data.get("trust_metrics", {}),
106
+ "trust_score": data.get("trust_score"),
107
+ "comment": data.get("comment"),
108
+ "timestamp": datetime.now().isoformat()
109
+ }
110
+
111
+ with open(STATS_FILE, "r+", encoding="utf-8") as f:
112
+ content = json.load(f)
113
+ content["evaluations"].append(record)
114
+ f.seek(0)
115
+ json.dump(content, f, indent=2, ensure_ascii=False)
116
+
117
+ return jsonify({"status": "ok"})
118
+
119
+ @app.route("/api/evaluations")
120
+ def get_evaluations():
121
+ with open(STATS_FILE, "r", encoding="utf-8") as f:
122
+ data = json.load(f)
123
+
124
+ # Normalisation métriques
125
+ mapping = {
126
+ "RA": "AR",
127
+ "EA": "AE",
128
+ "RE": "ESR",
129
+ "MCS": "SDM",
130
+ "MS": "SM"
131
+ }
132
+
133
+ for e in data.get("evaluations", []):
134
+ if "trust_metrics" in e:
135
+ e["trust_metrics"] = {
136
+ mapping.get(k, k): v for k, v in e["trust_metrics"].items()
137
+ }
138
+
139
+ return jsonify(data)
140
+
141
+ # --------------------------------------------------
142
+ # 📝 API – REVIEWS (qualitatif)
143
+ # --------------------------------------------------
144
+ @app.route("/api/reviews")
145
+ def get_reviews():
146
+ with open(REVIEW_FILE, "r", encoding="utf-8") as f:
147
+ return jsonify(json.load(f))
148
+
149
+ @app.route("/save_review", methods=["POST"])
150
+ def save_review():
151
+ data = request.json
152
+
153
+ review = {
154
+ "scenario_id": data.get("scenario_id"),
155
+ "reader": data.get("reader"),
156
+ "review": data.get("review"),
157
+ "timestamp": datetime.now().isoformat()
158
+ }
159
+
160
+ with open(REVIEW_FILE, "r+", encoding="utf-8") as f:
161
+ content = json.load(f)
162
+ content["reviews"].append(review)
163
+ f.seek(0)
164
+ json.dump(content, f, indent=2, ensure_ascii=False)
165
+
166
+ return jsonify({"status": "ok"})
167
+
168
+ # --------------------------------------------------
169
+ # 📂 ROUTES FICHIERS STATIQUES
170
+ # --------------------------------------------------
171
+ @app.route("/cross_reading/<path:filename>")
172
+ def serve_cross_reading(filename):
173
+ return send_from_directory(CROSS_READING_DIR, filename)
174
+
175
+ # --------------------------------------------------
176
+ # 🚀 MAIN
177
+ # --------------------------------------------------
178
+ if __name__ == "__main__":
179
+
180
+ print(f"🚀 Application : http://0.0.0.0:{PORT}")
181
+ print(f"📈 Cross Reading : http://0.0.0.0:{PORT}/cross_readers.html")
182
+
183
+ # Création dossiers
184
+ for folder in [CROSS_READING_DIR, TEMPLATES_DIR, STATIC_DIR, DATA_DIR]:
185
+ os.makedirs(folder, exist_ok=True)
186
+
187
+ # Initialisation fichiers
188
+ defaults = {
189
+ SCENARIOS_FILE: {"scenarios": []},
190
+ SCENARIOS_LIST_FILE: {"scenarios": []},
191
+ STATS_FILE: {"evaluations": []},
192
+ REVIEW_FILE: {"reviews": []},
193
+ CALIBRATION_FILE: {
194
+ "metrics": {
195
+ "AR": {"min": 0, "max": 5, "weight": 1},
196
+ "AE": {"min": 0, "max": 5, "weight": 1},
197
+ "ESR": {"min": 0, "max": 5, "weight": 1},
198
+ "SDM": {"min": 0, "max": 5, "weight": 1},
199
+ "SM": {"min": 0, "max": 5, "weight": 1}
200
+ }
201
+ }
202
+ }
203
+
204
+ for path, content in defaults.items():
205
+ if not os.path.exists(path):
206
+ with open(path, "w", encoding="utf-8") as f:
207
+ json.dump(content, f, indent=2, ensure_ascii=False)
208
+ print(f"📄 Créé : {path}")
209
+
210
+ app.run(
211
+ host="0.0.0.0",
212
+ port=PORT,
213
+ debug=True,
214
+ use_reloader=False
215
+ )