import os
import json
import threading
import time
import uuid
from datetime import datetime, timedelta
import zoneinfo
from flask import Flask, render_template_string, request, jsonify
from huggingface_hub import HfApi, hf_hub_download
from huggingface_hub.utils import RepositoryNotFoundError
app = Flask(__name__)
app.secret_key = os.getenv("FLASK_SECRET_KEY", "med_tracker_secret_key")
DATA_FILE = 'medications_data.json'
REPO_ID = os.getenv("REPO_ID", "Kgshop/clients")
HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
def load_data():
try:
hf_hub_download(
repo_id=REPO_ID,
filename=DATA_FILE,
repo_type="dataset",
token=HF_TOKEN_READ,
local_dir=".",
local_dir_use_symlinks=False
)
with open(DATA_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
if not isinstance(data, dict) or 'schedules' not in data:
return {'schedules': []}
return data
except Exception:
return {'schedules': []}
def save_data(data):
with open(DATA_FILE, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
try:
api = HfApi()
api.upload_file(
path_or_fileobj=DATA_FILE,
path_in_repo=DATA_FILE,
repo_id=REPO_ID,
repo_type="dataset",
token=HF_TOKEN_WRITE
)
except Exception:
pass
def periodic_backup():
while True:
try:
data = load_data()
save_data(data)
except Exception:
pass
time.sleep(800)
HTML_CONTENT = '''
MedTracker
'''
@app.route('/')
def index():
return render_template_string(HTML_CONTENT)
@app.route('/api/data', methods=['GET'])
def get_data():
return jsonify(load_data())
@app.route('/api/schedules/special', methods=['POST'])
def create_special():
data_req = request.json
start_date_str = data_req.get('start_date')
start_date = datetime.strptime(start_date_str, "%Y-%m-%d").date()
schedule = {
"id": str(uuid.uuid4()),
"name": "Пробиотик + Нистатин (42 дня)",
"start_date": start_date_str,
"days": []
}
for day_idx in range(42):
current_date = start_date + timedelta(days=day_idx)
day_data = {
"day_number": day_idx + 1,
"date": current_date.strftime("%Y-%m-%d"),
"doses": []
}
day_data["doses"].append({
"id": str(uuid.uuid4()), "medication": "Пробиотик", "label": "Утро", "taken": False, "taken_at": None
})
day_data["doses"].append({
"id": str(uuid.uuid4()), "medication": "Пробиотик", "label": "Вечер", "taken": False, "taken_at": None
})
if (7 <= day_idx < 21) or (28 <= day_idx < 42):
day_data["doses"].append({
"id": str(uuid.uuid4()), "medication": "Нистатин", "label": "Утро", "taken": False, "taken_at": None
})
day_data["doses"].append({
"id": str(uuid.uuid4()), "medication": "Нистатин", "label": "День", "taken": False, "taken_at": None
})
day_data["doses"].append({
"id": str(uuid.uuid4()), "medication": "Нистатин", "label": "Вечер", "taken": False, "taken_at": None
})
schedule["days"].append(day_data)
db = load_data()
db['schedules'].append(schedule)
save_data(db)
return jsonify({"status": "ok"})
@app.route('/api/schedules/custom', methods=['POST'])
def create_custom():
data_req = request.json
start_date_str = data_req.get('start_date')
name = data_req.get('name')
duration = int(data_req.get('duration'))
meds = data_req.get('meds')
start_date = datetime.strptime(start_date_str, "%Y-%m-%d").date()
schedule = {
"id": str(uuid.uuid4()),
"name": name,
"start_date": start_date_str,
"days": []
}
for day_idx in range(duration):
current_date = start_date + timedelta(days=day_idx)
day_data = {
"day_number": day_idx + 1,
"date": current_date.strftime("%Y-%m-%d"),
"doses": []
}
for med in meds:
times = int(med['times'])
for t in range(times):
day_data["doses"].append({
"id": str(uuid.uuid4()),
"medication": med['name'],
"label": f"Прием {t+1}",
"taken": False,
"taken_at": None
})
schedule["days"].append(day_data)
db = load_data()
db['schedules'].append(schedule)
save_data(db)
return jsonify({"status": "ok"})
@app.route('/api/toggle', methods=['POST'])
def toggle_dose():
data_req = request.json
sched_id = data_req.get('schedule_id')
dose_id = data_req.get('dose_id')
val = data_req.get('value')
db = load_data()
tz = zoneinfo.ZoneInfo("Asia/Almaty")
now_str = datetime.now(tz).strftime("%d.%m.%Y %H:%M")
for s in db['schedules']:
if s['id'] == sched_id:
for d in s['days']:
for dose in d['doses']:
if dose['id'] == dose_id:
dose['taken'] = val
dose['taken_at'] = now_str if val else None
save_data(db)
return jsonify({"status": "ok", "taken_at": dose['taken_at']})
return jsonify({"status": "error"}), 404
@app.route('/api/schedules/delete', methods=['POST'])
def delete_schedule():
data_req = request.json
sched_id = data_req.get('schedule_id')
db = load_data()
db['schedules'] = [s for s in db['schedules'] if s['id'] != sched_id]
save_data(db)
return jsonify({"status": "ok"})
if __name__ == '__main__':
backup_thread = threading.Thread(target=periodic_backup, daemon=True)
backup_thread.start()
try:
load_data()
except Exception:
pass
app.run(debug=False, host='0.0.0.0', port=7860)