Spaces:
Sleeping
Sleeping
Create app.py
Browse files
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()
|