SergeyO7 commited on
Commit
8dc699b
·
verified ·
1 Parent(s): aee7c90

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +153 -0
app.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import matplotlib.pyplot as plt
3
+ from skyfield.api import load, Topos
4
+ from datetime import datetime
5
+ from dateutil import parser
6
+ from io import BytesIO
7
+ from PIL import Image
8
+
9
+ # Russian translations for planets
10
+ planet_ru = {
11
+ 'Sun': 'Солнце', 'Moon': 'Луна', 'Mercury': 'Меркурий', 'Venus': 'Венера',
12
+ 'Mars': 'Марс', 'Jupiter': 'Юпитер', 'Saturn': 'Сатурн'
13
+ }
14
+
15
+ # Planet symbols for plotting
16
+ planet_symbols = {
17
+ 'Sun': '☉', 'Moon': '☾', 'Mercury': '☿', 'Venus': '♀',
18
+ 'Mars': '♂', 'Jupiter': '♃', 'Saturn': '♄'
19
+ }
20
+
21
+ # Parse date-time into ISO format
22
+ def parse_date_time(date_time_str):
23
+ try:
24
+ dt = parser.parse(date_time_str)
25
+ return dt.isoformat()
26
+ except ValueError:
27
+ return None
28
+
29
+ # Convert longitude to zodiac sign and degrees
30
+ def lon_to_sign(lon):
31
+ signs = ["Овен", "Телец", "Близнецы", "Рак", "Лев", "Дева",
32
+ "Весы", "Скорпион", "Стрелец", "Козерог", "Водолей", "Рыбы"]
33
+ sign_index = int(lon // 30)
34
+ degrees = int(lon % 30)
35
+ minutes = int((lon % 1) * 60)
36
+ return f"{signs[sign_index]} {degrees}°{minutes}'"
37
+
38
+ # Calculate PLadder and zone sizes
39
+ def PLadder_ZSizes(date_time_iso, lat, lon):
40
+ try:
41
+ dt = datetime.fromisoformat(date_time_iso)
42
+ if not 1900 <= dt.year <= 2050:
43
+ return {"error": "Дата вне диапазона (1900–2050)."}
44
+
45
+ planets = load('de421.bsp')
46
+ earth = planets['earth']
47
+ observer = earth + Topos(latitude_degrees=float(lat), longitude_degrees=float(lon))
48
+
49
+ planet_objects = {
50
+ 'Sun': planets['sun'], 'Moon': planets['moon'], 'Mercury': planets['mercury'],
51
+ 'Venus': planets['venus'], 'Mars': planets['mars'],
52
+ 'Jupiter': planets['jupiter barycenter'], 'Saturn': planets['saturn barycenter']
53
+ }
54
+
55
+ ts = load.timescale()
56
+ t = ts.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
57
+
58
+ longitudes = {}
59
+ for planet, obj in planet_objects.items():
60
+ astrometric = observer.at(t).observe(obj)
61
+ _, lon, _ = astrometric.apparent().ecliptic_latlon()
62
+ longitudes[planet] = lon.degrees
63
+
64
+ sorted_planets = sorted(longitudes.items(), key=lambda x: x[1])
65
+ PLadder = [p for p, _ in sorted_planets]
66
+ sorted_lons = [lon for _, lon in sorted_planets]
67
+
68
+ zone_sizes = [sorted_lons[0]] + [sorted_lons[i+1] - sorted_lons[i] for i in range(6)] + [360 - sorted_lons[6]]
69
+ bordering = [[PLadder[0]]] + [[PLadder[i-1], PLadder[i]] for i in range(1, 7)] + [[PLadder[6]]]
70
+
71
+ ZSizes = []
72
+ for i, size in enumerate(zone_sizes):
73
+ bord = bordering[i]
74
+ X = 7 if any(p in ['Sun', 'Moon'] for p in bord) else 6 if any(p in ['Mercury', 'Venus', 'Mars'] for p in bord) else 5
75
+ classification = ('Swallowed' if size <= 1 else 'Tiny' if size <= X else 'Small' if size <= 40 else
76
+ 'Ideal' if 50 <= size <= 52 else 'Normal' if size < 60 else 'Big')
77
+ d, m = int(size), int((size - int(size)) * 60)
78
+ ZSizes.append((f"{d}°{m}'", classification))
79
+
80
+ return {'PLadder': PLadder, 'ZSizes': ZSizes, 'longitudes': longitudes}
81
+
82
+ except ValueError:
83
+ return {"error": "Неверный формат даты и времени."}
84
+ except Exception as e:
85
+ return {"error": f"Ошибка: {str(e)}"}
86
+
87
+ # Plot the planetary ladder
88
+ def plot_pladder(PLadder):
89
+ fig, ax = plt.subplots()
90
+ ax.plot([0, 1.5, 3, 0], [0, 3, 0, 0], 'k-') # Triangle
91
+ ax.plot([0, 3], [1, 1], 'k--') # Horizontal lines
92
+ ax.plot([0, 3], [2, 2], 'k--')
93
+ positions = [(0.2, 0.2), (0.2, 1.2), (0.2, 2.2), (1.5, 3.2), (2.8, 2.2), (2.8, 1.2), (2.8, 0.2)]
94
+ for i, (x, y) in enumerate(positions):
95
+ ax.text(x, y, planet_symbols[PLadder[i]], ha='center', va='center', fontsize=24)
96
+ ax.set_xlim(-0.5, 3.5)
97
+ ax.set_ylim(-0.5, 3.5)
98
+ ax.set_aspect('equal')
99
+ ax.axis('off')
100
+ return fig
101
+
102
+ # Main interface function
103
+ def chat_interface(query, lat, lon):
104
+ if not query.startswith("PLadder "):
105
+ return "Запрос должен начинаться с 'PLadder' и содержать дату/время.", None
106
+
107
+ date_time_str = query.split(" ", 1)[1]
108
+ date_time_iso = parse_date_time(date_time_str)
109
+ if not date_time_iso:
110
+ return "Неверный формат даты и времени.", None
111
+
112
+ result = PLadder_ZSizes(date_time_iso, lat, lon)
113
+ if "error" in result:
114
+ return result["error"], None
115
+
116
+ PLadder = result["PLadder"]
117
+ ZSizes = result["ZSizes"]
118
+ longitudes = result["longitudes"]
119
+
120
+ planet_list = "\n".join([f"{planet_ru[p]}: {lon_to_sign(longitudes[p])}" for p in PLadder])
121
+ zones_text = "\n".join([f"Зона {i+1}: {size} ({cls})" for i, (size, cls) in enumerate(ZSizes)])
122
+
123
+ fig = plot_pladder(PLadder)
124
+ buf = BytesIO()
125
+ fig.savefig(buf, format='png', bbox_inches='tight')
126
+ buf.seek(0)
127
+ img = Image.open(buf)
128
+ plt.close(fig)
129
+
130
+ text = f"Планетарная лестница:\n{planet_list}\n\nРазмеры зон:\n{zones_text}"
131
+ return text, img
132
+
133
+ # Gradio UI
134
+ with gr.Blocks() as interface:
135
+ with gr.Row():
136
+ with gr.Column(scale=2):
137
+ output_text = gr.Textbox(label="Ответ", lines=10)
138
+ with gr.Column(scale=1):
139
+ output_image = gr.Image(label="График планетарной лестницы")
140
+ with gr.Row():
141
+ with gr.Column(scale=1):
142
+ query_text = gr.Textbox(label="Запрос", placeholder="Пример: PLadder 2023-10-10 12:00")
143
+ location_lat = gr.Textbox(label="Широта", placeholder="Пример: 37.7749")
144
+ location_lon = gr.Textbox(label="Долгота", placeholder="Пример: -122.4194")
145
+ submit_button = gr.Button("Отправить")
146
+
147
+ submit_button.click(
148
+ fn=chat_interface,
149
+ inputs=[query_text, location_lat, location_lon],
150
+ outputs=[output_text, output_image]
151
+ )
152
+
153
+ interface.launch()