SergeyO7 commited on
Commit
c40d32e
·
verified ·
1 Parent(s): dfb155a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +297 -286
app.py CHANGED
@@ -1,317 +1,328 @@
1
- from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool
2
- import smolagents # Added for aliasing
3
- # from smolagents.security import E2BSandbox
4
- import datetime
5
- import pytz
6
- import yaml
7
- from skyfield.api import load, Topos, load_file
8
- from skyfield import almanac
9
- from tools.final_answer import FinalAnswerTool
10
- from Gradio_UI import GradioUI
11
  import os
12
- import base64
13
-
14
- # Add the alias before instrumentation
15
- smolagents.ApiModel = smolagents.HfApiModel
16
-
17
- LANGFUSE_PUBLIC_KEY="pk-lf-133099c7-8644-49e8-8f6e-ec8bd6d543fd"
18
- LF_SECRET_KEY = os.environ["LANGFUSE_SECRET_KEY"]
19
- LANGFUSE_AUTH=base64.b64encode(f"{LANGFUSE_PUBLIC_KEY}:{LF_SECRET_KEY}".encode()).decode()
20
-
21
- os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://cloud.langfuse.com/api/public/otel" # EU data region
22
- # os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://us.cloud.langfuse.com/api/public/otel" # US data region
23
- os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}"
24
-
25
- from opentelemetry.sdk.trace import TracerProvider
26
- from openinference.instrumentation.smolagents import SmolagentsInstrumentor
27
- from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
28
- from opentelemetry.sdk.trace.export import SimpleSpanProcessor
29
-
30
- trace_provider = TracerProvider()
31
- trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter()))
32
-
33
- SmolagentsInstrumentor().instrument(tracer_provider=trace_provider)
34
-
35
- # Load ephemeris and timescale
36
- planets = load('https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/de440.bsp')
37
- ts = load.timescale()
38
-
39
- # Define Zodiac signs and their boundaries (0° to 360° ecliptic longitude)
40
- ZODIAC_SIGNS = [
41
- ("Aries", 0, 30),
42
- ("Taurus", 30, 60),
43
- ("Gemini", 60, 90),
44
- ("Cancer", 90, 120),
45
- ("Leo", 120, 150),
46
- ("Virgo", 150, 180),
47
- ("Libra", 180, 210),
48
- ("Scorpio", 210, 240),
49
- ("Sagittarius", 240, 270),
50
- ("Capricorn", 270, 300),
51
- ("Aquarius", 300, 330),
52
- ("Pisces", 330, 360),
53
- ]
54
-
55
- # Moon phase boundaries (0° to 360° phase angle) for display purposes
56
- MOON_PHASES = [
57
- ("New Moon", 0, 45),
58
- ("Waxing Crescent", 45, 90),
59
- ("First Quarter", 90, 135),
60
- ("Waxing Gibbous", 135, 180),
61
- ("Full Moon", 180, 225),
62
- ("Waning Gibbous", 225, 270),
63
- ("Last Quarter", 270, 315),
64
- ("Waning Crescent", 315, 360),
65
- ]
66
-
67
- # Fertility sign coefficients (applicable to all plants)
68
- FERTILITY_SIGN_COEFFS = {
69
- "Aries": 1,
70
- "Taurus": 2,
71
- "Gemini": 0,
72
- "Cancer": 2,
73
- "Leo": 1,
74
- "Virgo": 0,
75
- "Libra": 0.5,
76
- "Scorpio": 1.5,
77
- "Sagittarius": 1,
78
- "Capricorn": 1,
79
- "Aquarius": 0,
80
- "Pisces": 2,
81
- }
82
-
83
- # Pruning sign coefficients (applicable to all plants)
84
- PRUNING_SIGN_COEFFS = {
85
- "Aries": 1,
86
- "Taurus": 0,
87
- "Gemini": 2,
88
- "Cancer": 0,
89
- "Leo": 1,
90
- "Virgo": 2,
91
- "Libra": 1.5,
92
- "Scorpio": 0.5,
93
- "Sagittarius": 1,
94
- "Capricorn": 1,
95
- "Aquarius": 2,
96
- "Pisces": 0,
97
- }
98
-
99
- # Fertility phase coefficients for above-ground plants
100
- FERTILITY_PHASE_COEFFS_ABOVE = {
101
- "New Moon": 0,
102
- "Waxing Moon": 1,
103
- "Full Moon": 0,
104
- "Waning Moon": 0.5,
105
  }
106
 
107
- # Fertility phase coefficients for root crops
108
- FERTILITY_PHASE_COEFFS_ROOT = {
109
- "New Moon": 0,
110
- "Waxing Moon": 0.5,
111
- "Full Moon": 0,
112
- "Waning Moon": 1,
 
 
113
  }
114
 
115
- # Pruning phase coefficients
116
- PRUNING_PHASE_COEFFS = {
117
- "New Moon": 0,
118
- "Waxing Moon": 1,
119
- "Full Moon": 0,
120
- "Waning Moon": 0.5,
 
 
121
  }
122
 
123
- @tool
124
- def get_moon_info(date_time: str) -> dict:
125
- """
126
- Returns Moon's Zodiac position, phase, and fertility and pruning indices for the given date/time.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- The fertility and pruning indices are calculated as sum of sign and phase fertility values of the Moon position. Moon sign fertility
129
- amounts up to 2.0 value and phase fertility value could be 1.0 max.
130
- It is observed that when Moon is in different Zodiac signs, the fertility of new plants and impact of pruning differs.
131
- When Moon is in fertile sign the plant is in the active phase, when all processes are particularly intense, and any intervention
132
- such as pruning can be very traumatic for the plant. Here:
133
- Most fertile signs: Taurus, Pisces, Cancer - Plants are in the active growth phase, juices and nutrients actively circulate
134
- in the plant, and it is best time for fertilizers, harvasting cutting, vaccination, rooting.
135
- Conditionally fertile: Scorpio
136
- Neutral: Aries, Leo, Sagittarius, Capricorn
137
- Conditionally sterile: Libra
138
- Sterile: Gemini, Virgo, Aquarius
 
 
 
 
139
 
140
- Fertility indices ranges from 0.0 to 3.0 where proportionaly
141
- 0 - minimal expected fertility
142
- 3.0 - most favorable fertility for platining,
143
- and depends on type of plant (root crop or produce above ground).
 
 
144
 
145
- Pruning indices ranges from 0 to 3 where proportionaly:
146
- 0 - pruning is not recommended as it causes most damage to tree and can lead to:
147
- Increased sap production from the cut points
148
- Increased vulnerability to infections
149
- Delayed wound healing
150
- Possible weakening of the plant.
151
- Instead of pruning into fertile signs, you can do:
152
- Crown formation
153
- Pinching the shoots
154
- Removing dead branches
155
- Sanitary treatment
156
- 1.0 - pruning is not recommended,
157
- 2.0 - allowed only minimum or sanitary pruning,
158
- 3.0 - most favorable time for pruning.
159
  Args:
160
- date_time (str): ISO 8601 formatted datetime (YYYY-MM-DDTHH:MM:SS)
 
161
  Returns:
162
- dict: {
163
- "zodiac_position": "Leo 15°30'",
164
- "moon_phase": "Waxing Gibbous",
165
- "fertility_above_ground": 2.0,
166
- "fertility_root_crop": 1.5,
167
- "pruning": 2.0
168
- }
169
  """
170
  try:
171
- # Parse input datetime and localize to UTC
172
- user_time = datetime.datetime.strptime(date_time, "%Y-%m-%dT%H:%M:%S")
173
- user_time = pytz.utc.localize(user_time)
174
-
175
- # Use loaded ephemeris and timescale
176
- t = ts.from_datetime(user_time)
177
-
178
- # Define celestial bodies
179
  earth = planets['earth']
180
- moon = planets['moon']
181
- sun = planets['sun']
182
-
183
- # Calculate Moon's ecliptic longitude
184
- astrometric = earth.at(t).observe(moon)
185
- ecliptic_lat, ecliptic_lon, distance = astrometric.ecliptic_latlon()
186
- lon_deg = ecliptic_lon.degrees % 360
187
-
188
- # Calculate the phase angle using almanac.moon_phase
189
- phase = almanac.moon_phase(planets, t)
190
- phase_angle = phase.degrees
191
-
192
- # Determine Zodiac sign and position
193
- zodiac_sign = "Unknown"
194
- position_degrees = 0
195
- for sign, start, end in ZODIAC_SIGNS:
196
- if start <= lon_deg < end:
197
- zodiac_sign = sign
198
- position_degrees = lon_deg - start
199
- break
200
-
201
- # Format position to degrees and minutes
202
- degrees = int(position_degrees)
203
- minutes = int((position_degrees % 1) * 60)
204
- position_str = f"{zodiac_sign} {degrees}°{minutes:02}'"
205
-
206
- # Determine moon phase for display
207
- moon_phase = "Unknown"
208
- for phase, start, end in MOON_PHASES:
209
- if start <= phase_angle < end:
210
- moon_phase = phase
211
- break
212
-
213
- # Determine phase category for indices with 15° orbis for New and Full Moon
214
- if (phase_angle >= 345 or phase_angle < 15):
215
- phase_category = "New Moon" # 345° to 15° (30° total orbis)
216
- elif 15 <= phase_angle < 165:
217
- phase_category = "Waxing Moon"
218
- elif 165 <= phase_angle < 195:
219
- phase_category = "Full Moon" # 165° to 195° (30° total orbis)
220
- elif 195 <= phase_angle < 345:
221
- phase_category = "Waning Moon"
222
- else:
223
- phase_category = "Unknown"
224
-
225
- # Calculate fertility and pruning indices
226
- if zodiac_sign in FERTILITY_SIGN_COEFFS and phase_category in FERTILITY_PHASE_COEFFS_ABOVE:
227
- fertility_above_ground = FERTILITY_SIGN_COEFFS[zodiac_sign] + FERTILITY_PHASE_COEFFS_ABOVE[phase_category]
228
- fertility_root_crop = FERTILITY_SIGN_COEFFS[zodiac_sign] + FERTILITY_PHASE_COEFFS_ROOT[phase_category]
229
- pruning = PRUNING_SIGN_COEFFS[zodiac_sign] + PRUNING_PHASE_COEFFS[phase_category]
230
- else:
231
- fertility_above_ground = None
232
- fertility_root_crop = None
233
- pruning = None
234
-
235
- return {
236
- "zodiac_position": position_str,
237
- "moon_phase": moon_phase,
238
- "fertility_above_ground": fertility_above_ground,
239
- "fertility_root_crop": fertility_root_crop,
240
- "pruning": pruning
241
  }
242
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  except Exception as e:
244
- raise ValueError(f"Error in get_moon_info: {str(e)}")
245
 
246
- @tool
247
- def get_current_time_in_timezone(timezone: str) -> str:
248
  """
249
- Returns the current local time in the specified timezone with description.
 
250
  Args:
251
- timezone (str): A string representing a valid timezone (e.g., 'UTC')
 
252
  Returns:
253
- str: Formatted local time with timezone description
254
  """
255
- try:
256
- tz = pytz.timezone(timezone)
257
- now = datetime.datetime.now(tz)
258
- return f"Local time in {timezone}: {now.strftime('%Y-%m-%d %H:%M:%S')}"
259
- except Exception as e:
260
- return f"Error: {str(e)}"
261
-
262
- @tool
263
- def get_current_time_raw(timezone: str) -> str:
 
 
 
 
 
 
 
 
 
264
  """
265
- Returns current local time in specified timezone as ISO 8601 string.
 
266
  Args:
267
- timezone (str): A string representing a valid timezone (e.g., 'UTC')
 
268
  Returns:
269
- str: Datetime in ISO 8601 format (YYYY-MM-DDTHH:MM:SS)
270
  """
 
271
  try:
272
- tz = pytz.timezone(timezone)
273
- now = datetime.datetime.now(tz)
274
- return now.strftime("%Y-%m-%dT%H:%M:%S")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  except Exception as e:
276
- return f"Error: {str(e)}"
277
-
278
- # Model configuration
279
- final_answer = FinalAnswerTool()
280
- model = HfApiModel(
281
- max_tokens=2096,
282
- temperature=0.5,
283
- model_id="https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud/",
284
- custom_role_conversions=None,
285
- )
286
-
287
- # Load image tool from Hub
288
- image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
289
-
290
- # Load prompt templates
291
- with open("prompts.yaml", 'r') as stream:
292
- prompt_templates = yaml.safe_load(stream)
293
-
294
- # Initialize agent with all tools
295
- agent = CodeAgent(
296
- model=model,
297
- tools=[final_answer, get_moon_info, get_current_time_in_timezone, get_current_time_raw, image_generation_tool],
298
- max_steps=6,
299
- verbosity_level=1,
300
- prompt_templates=prompt_templates
301
- # execution_env=E2BSandbox(
302
- # allowed_imports=["numpy", "pandas"], # Explicitly permitted packages
303
- # blocked_imports=["subprocess"], # Prevent system access
304
- # ),
305
- # safe_mode=True, # Enable safe code execution
306
- # timeout=10, # Seconds before execution timeout
307
- # max_memory=512, # MB memory limit
308
- # file_system_access=False, # Disable disk write access
309
- # network_access=False, # Block network operations
310
- # max_code_iterations=100, # Prevent infinite loops
311
  )
312
 
313
  if __name__ == "__main__":
314
- GradioUI(agent).launch()
315
-
316
- # Change to your username and repo name
317
- # agent.push_to_hub('sergeyo7/Garden_Magus')
 
1
+ import gradio as gr
2
+ from langchain_community.document_loaders import UnstructuredMarkdownLoader
3
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
4
+ from langchain_core.documents import Document
5
+ from langchain_huggingface import HuggingFaceEmbeddings
6
+ from langchain_community.vectorstores import FAISS
7
+ from langchain_community.llms import HuggingFaceHub
8
+ from langchain.prompts import ChatPromptTemplate
9
+ from dotenv import load_dotenv
 
10
  import os
11
+ from datetime import datetime
12
+ from skyfield.api import load
13
+ import matplotlib.pyplot as plt
14
+
15
+ # Load environment variables
16
+ load_dotenv()
17
+
18
+ DATA_PATH = "" # Specify the path to your file
19
+ PROMPT_TEMPLATE = """
20
+ Ответь на вопрос, используя только следующий контекст:
21
+ {context}
22
+ ---
23
+ Ответь на вопрос на основе приведенного контекста: {question}
24
+ """
25
+
26
+ # Global variable for status
27
+ status_message = "Инициализация..."
28
+
29
+ # Translation dictionaries
30
+ classification_ru = {
31
+ 'Swallowed': 'проглоченная',
32
+ 'Tiny': 'сверхмалая',
33
+ 'Small': 'малая',
34
+ 'Normal': 'нормальная',
35
+ 'Ideal': 'идеальная',
36
+ 'Big': 'большая'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
 
39
+ planet_ru = {
40
+ 'Sun': 'Солнце',
41
+ 'Moon': 'Луна',
42
+ 'Mercury': 'Меркурий',
43
+ 'Venus': 'Венера',
44
+ 'Mars': 'Марс',
45
+ 'Jupiter': 'Юпитер',
46
+ 'Saturn': 'Сатурн'
47
  }
48
 
49
+ planet_symbols = {
50
+ 'Sun': '☉',
51
+ 'Moon': '☾',
52
+ 'Mercury': '☿',
53
+ 'Venus': '♀',
54
+ 'Mars': '♂',
55
+ 'Jupiter': '♃',
56
+ 'Saturn': '♄'
57
  }
58
 
59
+ def initialize_vectorstore():
60
+ """Initialize the FAISS vector store for document retrieval."""
61
+ global status_message
62
+ try:
63
+ status_message = "Загрузка и обработка документов..."
64
+ documents = load_documents()
65
+ chunks = split_text(documents)
66
+
67
+ status_message = "Создание векторной базы..."
68
+ vectorstore = save_to_faiss(chunks)
69
+
70
+ status_message = "База данных готова к использованию."
71
+ return vectorstore
72
+ except Exception as e:
73
+ status_message = f"Ошибка инициализации: {str(e)}"
74
+ raise
75
+
76
+ def load_documents():
77
+ """Load documents from the specified file path."""
78
+ file_path = os.path.join(DATA_PATH, "pl250320252.md")
79
+ if not os.path.exists(file_path):
80
+ raise FileNotFoundError(f"Файл {file_path} не найден")
81
+ loader = UnstructuredMarkdownLoader(file_path)
82
+ return loader.load()
83
+
84
+ def split_text(documents: list[Document]):
85
+ """Split documents into chunks for vectorization."""
86
+ text_splitter = RecursiveCharacterTextSplitter(
87
+ chunk_size=900,
88
+ chunk_overlap=300,
89
+ length_function=len,
90
+ add_start_index=True,
91
+ )
92
+ return text_splitter.split_documents(documents)
93
+
94
+ def save_to_faiss(chunks: list[Document]):
95
+ """Save document chunks to a FAISS vector store."""
96
+ embeddings = HuggingFaceEmbeddings(
97
+ model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
98
+ model_kwargs={'device': 'cpu'},
99
+ encode_kwargs={'normalize_embeddings': True}
100
+ )
101
+ return FAISS.from_documents(chunks, embeddings)
102
+
103
+ def process_query(query_text: str, vectorstore):
104
+ """Process a query using the RAG system."""
105
+ if vectorstore is None:
106
+ return "База данных не инициализирована", []
107
 
108
+ try:
109
+ results = vectorstore.similarity_search_with_relevance_scores(query_text, k=3)
110
+ global status_message
111
+ status_message += f"\nНайдено {len(results)} результатов"
112
+
113
+ if not results:
114
+ return "Не найдено результатов.", []
115
+
116
+ context_text = "\n\n---\n\n".join([
117
+ f"Релевантность: {score:.2f}\n{doc.page_content}"
118
+ for doc, score in results
119
+ ])
120
+
121
+ prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
122
+ prompt = prompt_template.format(context=context_text, question=query_text)
123
 
124
+ model = HuggingFaceHub(
125
+ repo_id="https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud/",
126
+ task="text2text-generation",
127
+ model_kwargs={"temperature": 0.5, "max_length": 512}
128
+ )
129
+ response_text = model.predict(prompt)
130
 
131
+ sources = list(set([doc.metadata.get("source", "") for doc, _ in results]))
132
+ return response_text, sources
133
+ except Exception as e:
134
+ return f"Ошибка обработки запроса: {str(e)}", []
135
+
136
+ def PLadder_ZSizes(date_time_iso: str):
137
+ """
138
+ Calculate the planetary ladder and zone sizes for a given date and time.
139
+
 
 
 
 
 
140
  Args:
141
+ date_time_iso (str): Date and time in ISO format (e.g., '2023-10-10T12:00:00')
142
+
143
  Returns:
144
+ dict: Contains 'PLadder' (list of planets) and 'ZSizes' (list of zone sizes with classifications)
145
+ or an error message if unsuccessful
 
 
 
 
 
146
  """
147
  try:
148
+ dt = datetime.fromisoformat(date_time_iso)
149
+ if dt.year < 1900 or dt.year > 2050:
150
+ return {"error": "Дата вне диапазона. Должна быть между 1900 и 2050 годами."}
151
+
152
+ # Load ephemeris
153
+ planets = load('de421.bsp')
 
 
154
  earth = planets['earth']
155
+
156
+ # Define planet objects
157
+ planet_objects = {
158
+ 'Sun': planets['sun'],
159
+ 'Moon': planets['moon'],
160
+ 'Mercury': planets['mercury'],
161
+ 'Venus': planets['venus'],
162
+ 'Mars': planets['mars'],
163
+ 'Jupiter': planets['jupiter barycenter'],
164
+ 'Saturn': planets['saturn barycenter']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  }
166
+
167
+ # Create time object
168
+ ts = load.timescale()
169
+ t = ts.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
170
+
171
+ # Compute ecliptic longitudes
172
+ longitudes = {}
173
+ for planet in planet_objects:
174
+ apparent = earth.at(t).observe(planet_objects[planet]).apparent()
175
+ _, lon, _ = apparent.ecliptic_latlon()
176
+ longitudes[planet] = lon.degrees
177
+
178
+ # Sort planets by longitude to form PLadder
179
+ sorted_planets = sorted(longitudes.items(), key=lambda x: x[1])
180
+ PLadder = [p for p, _ in sorted_planets]
181
+ sorted_lons = [lon for _, lon in sorted_planets]
182
+
183
+ # Calculate zone sizes
184
+ zone_sizes = [sorted_lons[0]] + [sorted_lons[i+1] - sorted_lons[i] for i in range(6)] + [360 - sorted_lons[6]]
185
+
186
+ # Determine bordering planets for classification
187
+ bordering = [[PLadder[0]]] + [[PLadder[i-1], PLadder[i]] for i in range(1, 7)] + [[PLadder[6]]]
188
+
189
+ # Classify each zone
190
+ ZSizes = []
191
+ for i, size in enumerate(zone_sizes):
192
+ bord = bordering[i]
193
+ if any(p in ['Sun', 'Moon'] for p in bord):
194
+ X = 7
195
+ elif any(p in ['Mercury', 'Venus', 'Mars'] for p in bord):
196
+ X = 6
197
+ else:
198
+ X = 5
199
+
200
+ if size <= 1:
201
+ classification = 'Swallowed'
202
+ elif size <= X:
203
+ classification = 'Tiny'
204
+ elif size <= 40:
205
+ classification = 'Small'
206
+ elif size < 60:
207
+ if 50 <= size <= 52:
208
+ classification = 'Ideal'
209
+ else:
210
+ classification = 'Normal'
211
+ else:
212
+ classification = 'Big'
213
+
214
+ # Convert size to degrees and minutes
215
+ d = int(size)
216
+ m = int((size - d) * 60)
217
+ size_str = f"{d}°{m}'"
218
+ ZSizes.append((size_str, classification))
219
+
220
+ return {'PLadder': PLadder, 'ZSizes': ZSizes}
221
+
222
+ except ValueError:
223
+ return {"error": "Неверный формат даты и времени. Используйте ISO формат, например, '2023-10-10T12:00:00'"}
224
  except Exception as e:
225
+ return {"error": f"Ошибка при вычислении: {str(e)}"}
226
 
227
+ def plot_pladder(PLadder):
 
228
  """
229
+ Plot the planetary ladder as a right triangle with planet symbols.
230
+
231
  Args:
232
+ PLadder (list): List of planet names in order
233
+
234
  Returns:
235
+ matplotlib.figure.Figure: The generated plot
236
  """
237
+ fig, ax = plt.subplots()
238
+ # Draw triangle with vertices (0,0), (0,3), (3,0)
239
+ ax.plot([0, 0, 3, 0], [0, 3, 0, 0], 'k-')
240
+ # Draw horizontal lines dividing height into three equal parts
241
+ ax.plot([0, 3], [1, 1], 'k--')
242
+ ax.plot([0, 3], [2, 2], 'k--')
243
+ # Define positions for planets 1 to 7
244
+ positions = [(0, 0), (0, 1), (0, 2), (0, 3), (1, 2), (2, 1), (3, 0)]
245
+ for i, pos in enumerate(positions):
246
+ symbol = planet_symbols[PLadder[i]]
247
+ ax.text(pos[0], pos[1], symbol, ha='center', va='center', fontsize=12)
248
+ ax.set_xlim(-0.5, 3.5)
249
+ ax.set_ylim(-0.5, 3.5)
250
+ ax.set_aspect('equal')
251
+ ax.axis('off')
252
+ return fig
253
+
254
+ def chat_interface(query_text):
255
  """
256
+ Handle user queries, either for planetary ladder or general RAG questions.
257
+
258
  Args:
259
+ query_text (str): User's input query
260
+
261
  Returns:
262
+ tuple: (text response, plot figure or None)
263
  """
264
+ global status_message
265
  try:
266
+ vectorstore = initialize_vectorstore()
267
+
268
+ if query_text.startswith("PLadder "):
269
+ # Extract date and time from query
270
+ date_time_iso = query_text.split(" ", 1)[1]
271
+ result = PLadder_ZSizes(date_time_iso)
272
+
273
+ if "error" in result:
274
+ return result["error"], None
275
+
276
+ PLadder = result["PLadder"]
277
+ ZSizes = result["ZSizes"]
278
+
279
+ # Translate to Russian
280
+ PLadder_ru = [planet_ru[p] for p in PLadder]
281
+ ZSizes_ru = [(size_str, classification_ru[classification]) for size_str, classification in ZSizes]
282
+
283
+ # Prepare queries and get responses
284
+ responses = []
285
+ for i in range(7):
286
+ planet = PLadder_ru[i]
287
+ size_str, class_ru = ZSizes_ru[i]
288
+ query = f"Что значит {planet} на {i+1}-й ступени и {size_str} {class_ru} {i+1}-я зона?"
289
+ response, _ = process_query(query, vectorstore)
290
+ responses.append(f"Интерпретация для {i+1}-й ступени и {i+1}-й зоны: {response}")
291
+
292
+ # Query for 8th zone
293
+ size_str, class_ru = ZSizes_ru[7]
294
+ query = f"Что значит {size_str} {class_ru} восьмая зона?"
295
+ response, _ = process_query(query, vectorstore)
296
+ responses.append(f"Интерпретация для 8-й зоны: {response}")
297
+
298
+ # Generate plot
299
+ fig = plot_pladder(PLadder)
300
+
301
+ # Compile response text
302
+ text = "Планетарная лестница: " + ", ".join(PLadder_ru) + "\n"
303
+ text += "Размеры зон:\n" + "\n".join([f"Зона {i+1}: {size_str} {class_ru}"
304
+ for i, (size_str, class_ru) in enumerate(ZSizes_ru)]) + "\n\n"
305
+ text += "\n".join(responses)
306
+ return text, fig
307
+
308
+ else:
309
+ # Handle regular RAG query
310
+ response, sources = process_query(query_text, vectorstore)
311
+ full_response = f"{status_message}\n\nОтвет: {response}\n\nИсточники: {', '.join(sources) if sources else 'Нет источников'}"
312
+ return full_response, None
313
+
314
  except Exception as e:
315
+ return f"Критическая ошибка: {str(e)}", None
316
+
317
+ # Define Gradio Interface
318
+ interface = gr.Interface(
319
+ fn=chat_interface,
320
+ inputs=gr.Textbox(lines=2, placeholder="Введите ваш вопрос здесь..."),
321
+ outputs=[gr.Textbox(), gr.Image()],
322
+ title="Чат с документами",
323
+ description="Задайте вопрос, и я отвечу на основе загруженных документов. "
324
+ "Для запроса планетарной лестницы используйте формат: PLadder YYYY-MM-DDTHH:MM:SS"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  )
326
 
327
  if __name__ == "__main__":
328
+ interface.launch()