wrd 0.1.41__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wrd/__init__.py +0 -0
- wrd/__main__.py +518 -0
- wrd-1.0.2.dist-info/METADATA +420 -0
- wrd-1.0.2.dist-info/RECORD +8 -0
- {wrd-0.1.41.dist-info → wrd-1.0.2.dist-info}/WHEEL +2 -1
- wrd-1.0.2.dist-info/entry_points.txt +2 -0
- wrd-1.0.2.dist-info/top_level.txt +1 -0
- dune/__init__.py +0 -31
- dune/__main__.py +0 -6
- dune/config_generator.py +0 -414
- dune/genconfig.py +0 -146
- dune/interactive_dune.py +0 -272
- dune/interactive_mapper.py +0 -599
- dune/llm_analyzer.py +0 -197
- dune/processor_engine.py +0 -114
- dune/smart_env_manager.py +0 -573
- dune/task_validator.py +0 -324
- wrd-0.1.41.dist-info/METADATA +0 -501
- wrd-0.1.41.dist-info/RECORD +0 -15
- wrd-0.1.41.dist-info/entry_points.txt +0 -3
- {wrd-0.1.41.dist-info → wrd-1.0.2.dist-info/licenses}/LICENSE +0 -0
dune/interactive_mapper.py
DELETED
@@ -1,599 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Interaktywny mapper zadań do bibliotek z automatycznym odpytywaniem o dane wejściowe.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import os
|
6
|
-
import sys
|
7
|
-
import subprocess
|
8
|
-
import importlib
|
9
|
-
import inspect
|
10
|
-
import ast
|
11
|
-
from typing import Dict, List, Any, Optional, Tuple
|
12
|
-
from dataclasses import dataclass
|
13
|
-
from pathlib import Path
|
14
|
-
from loguru import logger
|
15
|
-
import json
|
16
|
-
|
17
|
-
|
18
|
-
@dataclass
|
19
|
-
class LibraryInterface:
|
20
|
-
"""Definicja interfejsu biblioteki."""
|
21
|
-
name: str
|
22
|
-
package: str
|
23
|
-
main_function: str
|
24
|
-
required_params: List[str]
|
25
|
-
optional_params: List[str]
|
26
|
-
param_types: Dict[str, str]
|
27
|
-
param_descriptions: Dict[str, str]
|
28
|
-
examples: List[Dict[str, Any]]
|
29
|
-
cli_interface: Optional[str] = None
|
30
|
-
|
31
|
-
|
32
|
-
@dataclass
|
33
|
-
class TaskMapping:
|
34
|
-
"""Mapowanie zadania do bibliotek."""
|
35
|
-
task_keywords: List[str]
|
36
|
-
libraries: List[LibraryInterface]
|
37
|
-
priority: int = 1
|
38
|
-
|
39
|
-
|
40
|
-
class InteractiveMapper:
|
41
|
-
"""Interaktywny mapper zadań do bibliotek."""
|
42
|
-
|
43
|
-
def __init__(self):
|
44
|
-
self.library_database = self._build_library_database()
|
45
|
-
self.task_mappings = self._build_task_mappings()
|
46
|
-
self.discovered_interfaces = {}
|
47
|
-
|
48
|
-
def _build_library_database(self) -> Dict[str, LibraryInterface]:
|
49
|
-
"""Buduje bazę danych dostępnych bibliotek i ich interfejsów."""
|
50
|
-
|
51
|
-
return {
|
52
|
-
# Email processing
|
53
|
-
"imaplib": LibraryInterface(
|
54
|
-
name="IMAP Email Client",
|
55
|
-
package="imaplib",
|
56
|
-
main_function="IMAP4_SSL",
|
57
|
-
required_params=["server", "username", "password"],
|
58
|
-
optional_params=["port", "use_ssl", "folder"],
|
59
|
-
param_types={
|
60
|
-
"server": "str",
|
61
|
-
"username": "str",
|
62
|
-
"password": "str",
|
63
|
-
"port": "int",
|
64
|
-
"use_ssl": "bool",
|
65
|
-
"folder": "str"
|
66
|
-
},
|
67
|
-
param_descriptions={
|
68
|
-
"server": "Adres serwera IMAP (np. imap.gmail.com)",
|
69
|
-
"username": "Nazwa użytkownika/email",
|
70
|
-
"password": "Hasło do skrzynki",
|
71
|
-
"port": "Port serwera (143 dla IMAP, 993 dla IMAPS)",
|
72
|
-
"use_ssl": "Czy używać szyfrowania SSL",
|
73
|
-
"folder": "Folder do przetwarzania (domyślnie INBOX)"
|
74
|
-
},
|
75
|
-
examples=[
|
76
|
-
{
|
77
|
-
"server": "imap.gmail.com",
|
78
|
-
"username": "user@gmail.com",
|
79
|
-
"password": "app_password",
|
80
|
-
"port": 993,
|
81
|
-
"use_ssl": True
|
82
|
-
}
|
83
|
-
]
|
84
|
-
),
|
85
|
-
|
86
|
-
# Database access
|
87
|
-
"sqlalchemy": LibraryInterface(
|
88
|
-
name="SQL Database Access",
|
89
|
-
package="sqlalchemy",
|
90
|
-
main_function="create_engine",
|
91
|
-
required_params=["database_url"],
|
92
|
-
optional_params=["pool_size", "echo", "timeout"],
|
93
|
-
param_types={
|
94
|
-
"database_url": "str",
|
95
|
-
"pool_size": "int",
|
96
|
-
"echo": "bool",
|
97
|
-
"timeout": "int"
|
98
|
-
},
|
99
|
-
param_descriptions={
|
100
|
-
"database_url": "URL połączenia z bazą danych (postgresql://user:pass@host/db)",
|
101
|
-
"pool_size": "Rozmiar puli połączeń",
|
102
|
-
"echo": "Czy logować zapytania SQL",
|
103
|
-
"timeout": "Timeout połączenia w sekundach"
|
104
|
-
},
|
105
|
-
examples=[
|
106
|
-
{
|
107
|
-
"database_url": "postgresql://user:password@localhost:5432/mydb",
|
108
|
-
"pool_size": 5,
|
109
|
-
"echo": False
|
110
|
-
},
|
111
|
-
{
|
112
|
-
"database_url": "sqlite:///data.db"
|
113
|
-
}
|
114
|
-
]
|
115
|
-
),
|
116
|
-
|
117
|
-
# Web scraping
|
118
|
-
"requests": LibraryInterface(
|
119
|
-
name="HTTP Client",
|
120
|
-
package="requests",
|
121
|
-
main_function="get",
|
122
|
-
required_params=["url"],
|
123
|
-
optional_params=["headers", "timeout", "verify_ssl", "proxies"],
|
124
|
-
param_types={
|
125
|
-
"url": "str",
|
126
|
-
"headers": "dict",
|
127
|
-
"timeout": "int",
|
128
|
-
"verify_ssl": "bool",
|
129
|
-
"proxies": "dict"
|
130
|
-
},
|
131
|
-
param_descriptions={
|
132
|
-
"url": "URL do pobrania",
|
133
|
-
"headers": "Nagłówki HTTP (jako słownik)",
|
134
|
-
"timeout": "Timeout żądania w sekundach",
|
135
|
-
"verify_ssl": "Czy weryfikować certyfikaty SSL",
|
136
|
-
"proxies": "Konfiguracja proxy (jako słownik)"
|
137
|
-
},
|
138
|
-
examples=[
|
139
|
-
{
|
140
|
-
"url": "https://api.example.com/data",
|
141
|
-
"headers": {"User-Agent": "Dune Bot 1.0"},
|
142
|
-
"timeout": 30
|
143
|
-
}
|
144
|
-
]
|
145
|
-
),
|
146
|
-
|
147
|
-
# File processing
|
148
|
-
"pandas": LibraryInterface(
|
149
|
-
name="Data Analysis",
|
150
|
-
package="pandas",
|
151
|
-
main_function="read_csv",
|
152
|
-
required_params=["filepath"],
|
153
|
-
optional_params=["separator", "encoding", "header_row"],
|
154
|
-
param_types={
|
155
|
-
"filepath": "str",
|
156
|
-
"separator": "str",
|
157
|
-
"encoding": "str",
|
158
|
-
"header_row": "int"
|
159
|
-
},
|
160
|
-
param_descriptions={
|
161
|
-
"filepath": "Ścieżka do pliku CSV",
|
162
|
-
"separator": "Separator kolumn (domyślnie ',')",
|
163
|
-
"encoding": "Kodowanie pliku (np. utf-8, cp1250)",
|
164
|
-
"header_row": "Numer wiersza z nagłówkami (0 = pierwszy wiersz)"
|
165
|
-
},
|
166
|
-
examples=[
|
167
|
-
{
|
168
|
-
"filepath": "data.csv",
|
169
|
-
"separator": ",",
|
170
|
-
"encoding": "utf-8"
|
171
|
-
}
|
172
|
-
]
|
173
|
-
),
|
174
|
-
|
175
|
-
# Image processing
|
176
|
-
"pillow": LibraryInterface(
|
177
|
-
name="Image Processing",
|
178
|
-
package="Pillow",
|
179
|
-
main_function="Image.open",
|
180
|
-
required_params=["image_path"],
|
181
|
-
optional_params=["output_format", "quality", "resize_dimensions"],
|
182
|
-
param_types={
|
183
|
-
"image_path": "str",
|
184
|
-
"output_format": "str",
|
185
|
-
"quality": "int",
|
186
|
-
"resize_dimensions": "tuple"
|
187
|
-
},
|
188
|
-
param_descriptions={
|
189
|
-
"image_path": "Ścieżka do pliku obrazu",
|
190
|
-
"output_format": "Format wyjściowy (JPEG, PNG, WEBP)",
|
191
|
-
"quality": "Jakość kompresji (1-100 dla JPEG)",
|
192
|
-
"resize_dimensions": "Nowe wymiary jako (width, height)"
|
193
|
-
},
|
194
|
-
examples=[
|
195
|
-
{
|
196
|
-
"image_path": "input.jpg",
|
197
|
-
"output_format": "JPEG",
|
198
|
-
"quality": 85,
|
199
|
-
"resize_dimensions": (800, 600)
|
200
|
-
}
|
201
|
-
]
|
202
|
-
)
|
203
|
-
}
|
204
|
-
|
205
|
-
def _build_task_mappings(self) -> List[TaskMapping]:
|
206
|
-
"""Buduje mapowania zadań do bibliotek."""
|
207
|
-
|
208
|
-
return [
|
209
|
-
TaskMapping(
|
210
|
-
task_keywords=["email", "imap", "pop3", "skrzynka", "wiadomość", "poczta"],
|
211
|
-
libraries=[self.library_database["imaplib"]],
|
212
|
-
priority=1
|
213
|
-
),
|
214
|
-
TaskMapping(
|
215
|
-
task_keywords=["baza danych", "sql", "postgresql", "mysql", "sqlite"],
|
216
|
-
libraries=[self.library_database["sqlalchemy"]],
|
217
|
-
priority=1
|
218
|
-
),
|
219
|
-
TaskMapping(
|
220
|
-
task_keywords=["http", "api", "rest", "pobierz", "strona", "url"],
|
221
|
-
libraries=[self.library_database["requests"]],
|
222
|
-
priority=1
|
223
|
-
),
|
224
|
-
TaskMapping(
|
225
|
-
task_keywords=["csv", "excel", "pandas", "dataframe", "tabela", "dane"],
|
226
|
-
libraries=[self.library_database["pandas"]],
|
227
|
-
priority=1
|
228
|
-
),
|
229
|
-
TaskMapping(
|
230
|
-
task_keywords=["obraz", "zdjęcie", "jpg", "png", "resize", "grafika"],
|
231
|
-
libraries=[self.library_database["pillow"]],
|
232
|
-
priority=1
|
233
|
-
)
|
234
|
-
]
|
235
|
-
|
236
|
-
def analyze_task_and_map_libraries(self, natural_request: str) -> List[LibraryInterface]:
|
237
|
-
"""Analizuje zadanie i mapuje je do odpowiednich bibliotek."""
|
238
|
-
|
239
|
-
logger.info("🔍 Analizowanie zadania i mapowanie bibliotek...")
|
240
|
-
|
241
|
-
request_lower = natural_request.lower()
|
242
|
-
matched_libraries = []
|
243
|
-
|
244
|
-
# Znajdź pasujące mapowania
|
245
|
-
for mapping in self.task_mappings:
|
246
|
-
score = sum(1 for keyword in mapping.task_keywords
|
247
|
-
if keyword in request_lower)
|
248
|
-
|
249
|
-
if score > 0:
|
250
|
-
for library in mapping.libraries:
|
251
|
-
if library not in matched_libraries:
|
252
|
-
matched_libraries.append(library)
|
253
|
-
logger.info(f"📚 Znaleziono bibliotekę: {library.name} (score: {score})")
|
254
|
-
|
255
|
-
# Sortuj według priorytetu
|
256
|
-
matched_libraries.sort(key=lambda x: self._get_library_priority(x.name), reverse=True)
|
257
|
-
|
258
|
-
return matched_libraries
|
259
|
-
|
260
|
-
def _get_library_priority(self, library_name: str) -> int:
|
261
|
-
"""Zwraca priorytet biblioteki."""
|
262
|
-
priorities = {
|
263
|
-
"IMAP Email Client": 10,
|
264
|
-
"SQL Database Access": 9,
|
265
|
-
"HTTP Client": 8,
|
266
|
-
"Data Analysis": 7,
|
267
|
-
"Image Processing": 6
|
268
|
-
}
|
269
|
-
return priorities.get(library_name, 1)
|
270
|
-
|
271
|
-
def discover_cli_interface(self, package_name: str) -> Optional[Dict[str, Any]]:
|
272
|
-
"""Odkrywa interfejs CLI biblioteki poprzez analizę kodu."""
|
273
|
-
|
274
|
-
if package_name in self.discovered_interfaces:
|
275
|
-
return self.discovered_interfaces[package_name]
|
276
|
-
|
277
|
-
logger.info(f"🔎 Odkrywanie interfejsu CLI dla {package_name}...")
|
278
|
-
|
279
|
-
try:
|
280
|
-
# Spróbuj zaimportować pakiet
|
281
|
-
module = importlib.import_module(package_name)
|
282
|
-
|
283
|
-
# Sprawdź czy ma CLI
|
284
|
-
cli_info = self._analyze_module_for_cli(module)
|
285
|
-
|
286
|
-
if cli_info:
|
287
|
-
self.discovered_interfaces[package_name] = cli_info
|
288
|
-
logger.success(f"✅ Odkryto interfejs CLI dla {package_name}")
|
289
|
-
return cli_info
|
290
|
-
|
291
|
-
except ImportError:
|
292
|
-
logger.warning(f"⚠️ Pakiet {package_name} nie jest zainstalowany")
|
293
|
-
except Exception as e:
|
294
|
-
logger.warning(f"⚠️ Błąd analizy {package_name}: {e}")
|
295
|
-
|
296
|
-
return None
|
297
|
-
|
298
|
-
def _analyze_module_for_cli(self, module) -> Optional[Dict[str, Any]]:
|
299
|
-
"""Analizuje moduł w poszukiwaniu interfejsu CLI."""
|
300
|
-
|
301
|
-
cli_info = {
|
302
|
-
"has_cli": False,
|
303
|
-
"main_functions": [],
|
304
|
-
"cli_commands": [],
|
305
|
-
"parameters": []
|
306
|
-
}
|
307
|
-
|
308
|
-
# Sprawdź główne funkcje modułu
|
309
|
-
for name, obj in inspect.getmembers(module):
|
310
|
-
if inspect.isfunction(obj) and not name.startswith('_'):
|
311
|
-
sig = inspect.signature(obj)
|
312
|
-
params = []
|
313
|
-
|
314
|
-
for param_name, param in sig.parameters.items():
|
315
|
-
param_info = {
|
316
|
-
"name": param_name,
|
317
|
-
"type": str(param.annotation) if param.annotation != param.empty else "Any",
|
318
|
-
"default": param.default if param.default != param.empty else None,
|
319
|
-
"required": param.default == param.empty
|
320
|
-
}
|
321
|
-
params.append(param_info)
|
322
|
-
|
323
|
-
cli_info["main_functions"].append({
|
324
|
-
"name": name,
|
325
|
-
"parameters": params,
|
326
|
-
"docstring": obj.__doc__
|
327
|
-
})
|
328
|
-
|
329
|
-
if cli_info["main_functions"]:
|
330
|
-
cli_info["has_cli"] = True
|
331
|
-
|
332
|
-
return cli_info if cli_info["has_cli"] else None
|
333
|
-
|
334
|
-
def interactive_parameter_collection(self, library: LibraryInterface) -> Dict[str, Any]:
|
335
|
-
"""Interaktywnie zbiera parametry dla biblioteki."""
|
336
|
-
|
337
|
-
logger.info(f"📝 Zbieranie parametrów dla: {library.name}")
|
338
|
-
print(f"\n🔧 KONFIGURACJA: {library.name}")
|
339
|
-
print("=" * 50)
|
340
|
-
|
341
|
-
if library.param_descriptions:
|
342
|
-
print("📋 Opis biblioteki:")
|
343
|
-
for param, desc in library.param_descriptions.items():
|
344
|
-
if param in library.required_params:
|
345
|
-
print(f" • {param} (wymagany): {desc}")
|
346
|
-
else:
|
347
|
-
print(f" • {param} (opcjonalny): {desc}")
|
348
|
-
|
349
|
-
# Pokaż przykłady
|
350
|
-
if library.examples:
|
351
|
-
print(f"\n💡 Przykład konfiguracji:")
|
352
|
-
example = library.examples[0]
|
353
|
-
for key, value in example.items():
|
354
|
-
print(f" {key} = {value}")
|
355
|
-
|
356
|
-
print("\n" + "=" * 50)
|
357
|
-
|
358
|
-
collected_params = {}
|
359
|
-
|
360
|
-
# Zbierz wymagane parametry
|
361
|
-
for param in library.required_params:
|
362
|
-
collected_params[param] = self._collect_single_parameter(
|
363
|
-
param, library, required=True
|
364
|
-
)
|
365
|
-
|
366
|
-
# Zbierz opcjonalne parametry (zapytaj czy user chce)
|
367
|
-
if library.optional_params:
|
368
|
-
print(f"\n🔧 Parametry opcjonalne:")
|
369
|
-
for param in library.optional_params:
|
370
|
-
if self._ask_yes_no(f"Czy chcesz skonfigurować {param}?"):
|
371
|
-
collected_params[param] = self._collect_single_parameter(
|
372
|
-
param, library, required=False
|
373
|
-
)
|
374
|
-
|
375
|
-
return collected_params
|
376
|
-
|
377
|
-
def _collect_single_parameter(self, param_name: str, library: LibraryInterface,
|
378
|
-
required: bool = True) -> Any:
|
379
|
-
"""Zbiera pojedynczy parametr."""
|
380
|
-
|
381
|
-
# Sprawdź czy jest w zmiennych środowiskowych
|
382
|
-
env_variants = [
|
383
|
-
param_name.upper(),
|
384
|
-
f"{library.package.upper()}_{param_name.upper()}",
|
385
|
-
f"DUNE_{param_name.upper()}"
|
386
|
-
]
|
387
|
-
|
388
|
-
env_value = None
|
389
|
-
env_source = None
|
390
|
-
|
391
|
-
for env_var in env_variants:
|
392
|
-
env_value = os.getenv(env_var)
|
393
|
-
if env_value:
|
394
|
-
env_source = env_var
|
395
|
-
break
|
396
|
-
|
397
|
-
# Przygotuj prompt
|
398
|
-
param_desc = library.param_descriptions.get(param_name, "")
|
399
|
-
param_type = library.param_types.get(param_name, "str")
|
400
|
-
|
401
|
-
prompt = f"📌 {param_name}"
|
402
|
-
if param_desc:
|
403
|
-
prompt += f" ({param_desc})"
|
404
|
-
if not required:
|
405
|
-
prompt += " [opcjonalny]"
|
406
|
-
|
407
|
-
if env_value:
|
408
|
-
prompt += f" [znaleziono w {env_source}: {env_value}]"
|
409
|
-
if self._ask_yes_no(f"Użyć wartości z {env_source}?", default=True):
|
410
|
-
return self._convert_type(env_value, param_type)
|
411
|
-
|
412
|
-
# Pobierz od użytkownika
|
413
|
-
while True:
|
414
|
-
try:
|
415
|
-
user_input = input(f"{prompt}: ").strip()
|
416
|
-
|
417
|
-
if not user_input and not required:
|
418
|
-
return None
|
419
|
-
|
420
|
-
if not user_input and required:
|
421
|
-
print("❌ Ten parametr jest wymagany!")
|
422
|
-
continue
|
423
|
-
|
424
|
-
return self._convert_type(user_input, param_type)
|
425
|
-
|
426
|
-
except KeyboardInterrupt:
|
427
|
-
print("\n⚠️ Przerwano przez użytkownika")
|
428
|
-
sys.exit(1)
|
429
|
-
except Exception as e:
|
430
|
-
print(f"❌ Błąd: {e}. Spróbuj ponownie.")
|
431
|
-
|
432
|
-
def _convert_type(self, value: str, param_type: str) -> Any:
|
433
|
-
"""Konwertuje wartość do odpowiedniego typu."""
|
434
|
-
|
435
|
-
if param_type == "int":
|
436
|
-
return int(value)
|
437
|
-
elif param_type == "bool":
|
438
|
-
return value.lower() in ["true", "1", "yes", "tak", "y"]
|
439
|
-
elif param_type == "float":
|
440
|
-
return float(value)
|
441
|
-
elif param_type == "list":
|
442
|
-
return value.split(",")
|
443
|
-
elif param_type == "dict":
|
444
|
-
return json.loads(value)
|
445
|
-
elif param_type == "tuple" and "," in value:
|
446
|
-
return tuple(map(int, value.split(",")))
|
447
|
-
else:
|
448
|
-
return value
|
449
|
-
|
450
|
-
def _ask_yes_no(self, question: str, default: bool = None) -> bool:
|
451
|
-
"""Zadaje pytanie tak/nie."""
|
452
|
-
|
453
|
-
if default is True:
|
454
|
-
prompt = f"{question} [T/n]: "
|
455
|
-
elif default is False:
|
456
|
-
prompt = f"{question} [t/N]: "
|
457
|
-
else:
|
458
|
-
prompt = f"{question} [t/n]: "
|
459
|
-
|
460
|
-
while True:
|
461
|
-
try:
|
462
|
-
answer = input(prompt).strip().lower()
|
463
|
-
|
464
|
-
if not answer and default is not None:
|
465
|
-
return default
|
466
|
-
|
467
|
-
if answer in ["t", "tak", "y", "yes", "1", "true"]:
|
468
|
-
return True
|
469
|
-
elif answer in ["n", "nie", "no", "0", "false"]:
|
470
|
-
return False
|
471
|
-
else:
|
472
|
-
print("Odpowiedz 't' (tak) lub 'n' (nie)")
|
473
|
-
|
474
|
-
except KeyboardInterrupt:
|
475
|
-
print("\n⚠️ Przerwano przez użytkownika")
|
476
|
-
sys.exit(1)
|
477
|
-
|
478
|
-
def generate_runtime_config(self, libraries: List[LibraryInterface],
|
479
|
-
collected_params: Dict[str, Dict[str, Any]]) -> Dict[str, Any]:
|
480
|
-
"""Generuje konfigurację runtime na podstawie zebranych danych."""
|
481
|
-
|
482
|
-
# Zbierz wszystkie wymagane pakiety
|
483
|
-
packages = {"required": [], "optional": []}
|
484
|
-
env_vars = {"required": [], "optional": []}
|
485
|
-
|
486
|
-
for library in libraries:
|
487
|
-
packages["required"].append(library.package)
|
488
|
-
|
489
|
-
# Dodaj zmienne środowiskowe na podstawie parametrów
|
490
|
-
lib_params = collected_params.get(library.name, {})
|
491
|
-
for param_name, value in lib_params.items():
|
492
|
-
env_var = f"{library.package.upper()}_{param_name.upper()}"
|
493
|
-
if param_name in library.required_params:
|
494
|
-
env_vars["required"].append(env_var)
|
495
|
-
else:
|
496
|
-
env_vars["optional"].append(env_var)
|
497
|
-
|
498
|
-
# Usuń duplikaty
|
499
|
-
packages["required"] = list(set(packages["required"]))
|
500
|
-
packages["optional"] = list(set(packages["optional"]))
|
501
|
-
env_vars["required"] = list(set(env_vars["required"]))
|
502
|
-
env_vars["optional"] = list(set(env_vars["optional"]))
|
503
|
-
|
504
|
-
return {
|
505
|
-
"runtime": {
|
506
|
-
"type": "docker",
|
507
|
-
"base_image": "python:3.11-slim",
|
508
|
-
"python_packages": packages,
|
509
|
-
"environment": env_vars
|
510
|
-
},
|
511
|
-
"collected_parameters": collected_params
|
512
|
-
}
|
513
|
-
|
514
|
-
def save_parameters_to_env(self, collected_params: Dict[str, Dict[str, Any]],
|
515
|
-
env_file: str = ".env") -> None:
|
516
|
-
"""Zapisuje zebrane parametry do pliku .env."""
|
517
|
-
|
518
|
-
logger.info(f"💾 Zapisywanie parametrów do {env_file}")
|
519
|
-
|
520
|
-
# Wczytaj istniejący .env jeśli istnieje
|
521
|
-
existing_vars = {}
|
522
|
-
if os.path.exists(env_file):
|
523
|
-
with open(env_file, 'r') as f:
|
524
|
-
for line in f:
|
525
|
-
line = line.strip()
|
526
|
-
if '=' in line and not line.startswith('#'):
|
527
|
-
key, value = line.split('=', 1)
|
528
|
-
existing_vars[key] = value
|
529
|
-
|
530
|
-
# Dodaj nowe zmienne
|
531
|
-
new_vars = {}
|
532
|
-
for lib_name, params in collected_params.items():
|
533
|
-
for param_name, value in params.items():
|
534
|
-
if value is not None:
|
535
|
-
# Kilka wariantów nazwy zmiennej
|
536
|
-
env_var = f"DUNE_{param_name.upper()}"
|
537
|
-
new_vars[env_var] = str(value)
|
538
|
-
|
539
|
-
# Połącz i zapisz
|
540
|
-
all_vars = {**existing_vars, **new_vars}
|
541
|
-
|
542
|
-
with open(env_file, 'w') as f:
|
543
|
-
f.write("# Dune Configuration\n")
|
544
|
-
f.write("# Auto-generated parameters\n\n")
|
545
|
-
|
546
|
-
for key, value in sorted(all_vars.items()):
|
547
|
-
f.write(f"{key}={value}\n")
|
548
|
-
|
549
|
-
logger.success(f"✅ Parametry zapisane do {env_file}")
|
550
|
-
print(f"\n💾 Zapisano {len(new_vars)} nowych parametrów do {env_file}")
|
551
|
-
|
552
|
-
def run_interactive_mapping(self, natural_request: str) -> Dict[str, Any]:
|
553
|
-
"""Uruchamia pełny interaktywny proces mapowania."""
|
554
|
-
|
555
|
-
print("\n" + "=" * 60)
|
556
|
-
print("🤖 DUNE - INTERAKTYWNY MAPPER BIBLIOTEK")
|
557
|
-
print("=" * 60)
|
558
|
-
print(f"📝 Zadanie: {natural_request}")
|
559
|
-
print("=" * 60)
|
560
|
-
|
561
|
-
# 1. Mapuj biblioteki
|
562
|
-
libraries = self.analyze_task_and_map_libraries(natural_request)
|
563
|
-
|
564
|
-
if not libraries:
|
565
|
-
print("❌ Nie znaleziono pasujących bibliotek dla tego zadania")
|
566
|
-
return {}
|
567
|
-
|
568
|
-
print(f"\n📚 Znalezione biblioteki ({len(libraries)}):")
|
569
|
-
for i, lib in enumerate(libraries, 1):
|
570
|
-
print(f" {i}. {lib.name} ({lib.package})")
|
571
|
-
|
572
|
-
# 2. Zbierz parametry dla każdej biblioteki
|
573
|
-
collected_params = {}
|
574
|
-
|
575
|
-
for library in libraries:
|
576
|
-
if self._ask_yes_no(f"\nKonfigurować {library.name}?", default=True):
|
577
|
-
params = self.interactive_parameter_collection(library)
|
578
|
-
collected_params[library.name] = params
|
579
|
-
|
580
|
-
# 3. Generuj konfigurację
|
581
|
-
runtime_config = self.generate_runtime_config(libraries, collected_params)
|
582
|
-
|
583
|
-
# 4. Zapisz do .env
|
584
|
-
if collected_params and self._ask_yes_no("\nZapisać parametry do .env?", default=True):
|
585
|
-
self.save_parameters_to_env(collected_params)
|
586
|
-
|
587
|
-
print("\n" + "=" * 60)
|
588
|
-
print("✅ MAPOWANIE ZAKOŃCZONE POMYŚLNIE!")
|
589
|
-
print("=" * 60)
|
590
|
-
print(f"📦 Pakiety do zainstalowania: {len(runtime_config['runtime']['python_packages']['required'])}")
|
591
|
-
print(f"🔧 Parametrów zebranych: {sum(len(params) for params in collected_params.values())}")
|
592
|
-
print("=" * 60)
|
593
|
-
|
594
|
-
return {
|
595
|
-
"libraries": libraries,
|
596
|
-
"parameters": collected_params,
|
597
|
-
"runtime_config": runtime_config,
|
598
|
-
"natural_request": natural_request
|
599
|
-
}
|