# /// script # requires-python = ">=3.13" # dependencies = [ # "flask", # ] # /// import socket def find_free_port(start=5000, max_tries=100): """ 從 start 開始找一個未被監聽的 TCP 端口,最多嘗試 max_tries 次 """ port = start for _ in range(max_tries): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if s.connect_ex(('0.0.0.0', port)) != 0: return port port += 1 raise RuntimeError(f"在 {start}–{start+max_tries} 範圍內找不到可用端口") import json from flask import Flask, request, Response from converter import Converter app = Flask(__name__) conv = Converter() @app.route('/solar2lunar', methods=['GET']) def solar2lunar_endpoint(): date_str = request.args.get('date') if not date_str: return Response(json.dumps({'error': '缺少參數 date,格式 YYYY-MM-DD'}), mimetype='application/json; charset=utf-8'), 400 try: info_raw = conv.solar_to_lunar(date_str) info = { 'gregorian': info_raw['西曆'], # Gregorian date 'lunar': info_raw['農曆'], # Lunar date 'ganzhi': info_raw['干支'], # Heavenly Stem and Earthly Branch 'zodiac': info_raw['生肖'], # Zodiac animal 'solar_term': info_raw['節氣'] # Solar term } return Response(json.dumps(info, ensure_ascii=False), mimetype='application/json; charset=utf-8') except Exception as e: return Response(json.dumps({'error': str(e)}, ensure_ascii=False), mimetype='application/json; charset=utf-8'), 400 @app.route('/lunar2solar', methods=['GET']) def lunar2solar_endpoint(): date_str = request.args.get('date') leap_str = request.args.get('leap', 'false') if not date_str: return Response(json.dumps({'error': '缺少參數 date,格式 YYYY-MM-DD'}), mimetype='application/json; charset=utf-8'), 400 leap = leap_str.lower() in ('1', 'true', 'yes') try: y_str, m_str, d_str = date_str.split('-', 2) y, m, d = int(y_str), int(m_str), int(d_str) except Exception: return Response(json.dumps({'error': '農曆日期格式應為 YYYY-MM-DD,閏月請加 leap=true'}), mimetype='application/json; charset=utf-8'), 400 try: solar_date = conv.lunar_to_solar(y, m, d, leap) info_raw = conv.solar_to_lunar(solar_date) info = { 'gregorian': info_raw['西曆'], 'lunar': info_raw['農曆'], 'ganzhi': info_raw['干支'], 'zodiac': info_raw['生肖'], 'solar_term': info_raw['節氣'] } return Response(json.dumps(info, ensure_ascii=False), mimetype='application/json; charset=utf-8') except Exception as e: return Response(json.dumps({'error': str(e)}, ensure_ascii=False), mimetype='application/json; charset=utf-8'), 400 if __name__ == '__main__': port = find_free_port(5000) print(f"使用埠 {port} 啟動服務…") app.run(host='0.0.0.0', port=port)