handycode 2.1.0__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.
handycode/config.py ADDED
@@ -0,0 +1,78 @@
1
+ """
2
+ Управление конфигурацией HandyCode (без внешних зависимостей)
3
+ """
4
+
5
+ import os
6
+ import json
7
+ from pathlib import Path
8
+
9
+
10
+ class Config:
11
+ """Управляет конфигурацией HandyCode"""
12
+
13
+ def __init__(self):
14
+ self.config_dir = Path.home() / '.handycode'
15
+ self.config_dir.mkdir(exist_ok=True)
16
+
17
+ self.env_file = self.config_dir / '.env'
18
+ self.config_file = self.config_dir / 'config.json'
19
+
20
+ self.config = self._load_config()
21
+
22
+ def _load_config(self) -> dict:
23
+ default_config = {
24
+ "default_model": "deepseek",
25
+ "auto_approve": False,
26
+ "language": "ru",
27
+ "installed_version": "2.0.0",
28
+ }
29
+
30
+ if self.config_file.exists():
31
+ try:
32
+ with open(self.config_file, encoding='utf-8') as f:
33
+ loaded = json.load(f)
34
+ default_config.update(loaded)
35
+ except:
36
+ pass
37
+
38
+ return default_config
39
+
40
+ def save_config(self):
41
+ with open(self.config_file, 'w', encoding='utf-8') as f:
42
+ json.dump(self.config, f, indent=2, ensure_ascii=False)
43
+
44
+ def get_api_key(self) -> str:
45
+ api_key = os.getenv('OPENROUTER_API_KEY')
46
+ if api_key:
47
+ return api_key
48
+
49
+ if self.env_file.exists():
50
+ try:
51
+ with open(self.env_file, encoding='utf-8') as f:
52
+ for line in f:
53
+ if line.startswith('OPENROUTER_API_KEY='):
54
+ key = line.split('=', 1)[1].strip()
55
+ if key:
56
+ return key
57
+ except:
58
+ pass
59
+
60
+ if 'api_key' in self.config and self.config['api_key']:
61
+ return self.config['api_key']
62
+
63
+ print("\nAPI ключ не найден!")
64
+ print("Получите ключ на: https://openrouter.ai/keys")
65
+ api_key = input("Введите API ключ: ").strip()
66
+
67
+ if api_key:
68
+ try:
69
+ with open(self.env_file, 'w', encoding='utf-8') as f:
70
+ f.write(f'OPENROUTER_API_KEY={api_key}\n')
71
+ os.chmod(self.env_file, 0o600)
72
+ except:
73
+ pass
74
+
75
+ return api_key
76
+
77
+ def get(self, key: str, default=None):
78
+ return self.config.get(key, default)
@@ -0,0 +1,238 @@
1
+ """
2
+ Управление файлами для HandyCode
3
+ """
4
+
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ from pathlib import Path
9
+ from typing import List, Dict, Optional
10
+ from datetime import datetime
11
+
12
+ from handycode.utils import print_success, print_error, print_warning, print_info
13
+
14
+
15
+ class FileManager:
16
+ """Управляет файловыми операциями HandyCode"""
17
+
18
+ def __init__(self, project_root: Path):
19
+ """Инициализация файлового менеджера"""
20
+ self.project_root = Path(project_root).resolve()
21
+ self.allowed_extensions = {
22
+ '.html', '.css', '.scss', '.sass', '.less',
23
+ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
24
+ '.vue', '.svelte', '.astro',
25
+ '.py', '.pyi', '.pyx', '.pxd',
26
+ '.json', '.yaml', '.yml', '.toml', '.ini', '.cfg',
27
+ '.xml', '.env', '.gitignore', '.dockerignore',
28
+ '.md', '.mdx', '.rst', '.txt', '.log',
29
+ '.sql', '.sh', '.bash', '.zsh', '.bat', '.ps1',
30
+ '.java', '.kt', '.scala',
31
+ '.cpp', '.c', '.h', '.hpp', '.cs',
32
+ '.rs', '.go', '.rb', '.php', '.swift',
33
+ '.dart', '.r', '.jl', '.lua',
34
+ '.dockerfile', '.makefile', '.cmake',
35
+ }
36
+
37
+ self.excluded_dirs = {
38
+ 'node_modules', '__pycache__', '.git', '.svn',
39
+ 'venv', '.venv', 'env', '.env',
40
+ 'dist', 'build', '.next', '.nuxt',
41
+ 'target', 'out', '.idea', '.vscode',
42
+ '.DS_Store', 'Thumbs.db',
43
+ }
44
+
45
+ def scan_project(self) -> str:
46
+ """Сканирует проект и возвращает структуру"""
47
+ if not self.project_root.exists():
48
+ return ""
49
+
50
+ try:
51
+ lines = [f"📁 Проект: {self.project_root.name}"]
52
+
53
+ # Собираем все файлы
54
+ all_files = []
55
+ for ext in self.allowed_extensions:
56
+ all_files.extend(self.project_root.rglob(f"*{ext}"))
57
+
58
+ # Фильтруем исключённые
59
+ files = [
60
+ f for f in all_files
61
+ if f.is_file() and not any(ex in f.parts for ex in self.excluded_dirs)
62
+ ]
63
+
64
+ lines.append(f"📄 Файлов: {len(files)}")
65
+
66
+ # Строим дерево
67
+ if files:
68
+ lines.append("\n📂 Структура:")
69
+ tree = self._build_tree(files)
70
+ lines.extend(self._print_tree(tree))
71
+
72
+ # Ключевые файлы
73
+ key_files = [
74
+ 'package.json', 'requirements.txt', 'Dockerfile',
75
+ 'README.md', 'setup.py', 'pyproject.toml',
76
+ 'tsconfig.json', '.gitignore', 'docker-compose.yml',
77
+ 'main.py', 'app.py', 'index.js', 'server.js'
78
+ ]
79
+
80
+ for file in files:
81
+ if file.name in key_files:
82
+ try:
83
+ content = file.read_text(encoding='utf-8')
84
+ if len(content) < 5000:
85
+ lines.append(f"\n{'=' * 40}")
86
+ lines.append(f"📄 {file.relative_to(self.project_root)}")
87
+ lines.append('=' * 40)
88
+ lines.append(content)
89
+ except:
90
+ pass
91
+
92
+ return '\n'.join(lines)
93
+ except Exception as e:
94
+ return f"Ошибка сканирования: {e}"
95
+
96
+ def _build_tree(self, files: List[Path]) -> dict:
97
+ """Строит дерево директорий"""
98
+ tree = {}
99
+ for file in files:
100
+ try:
101
+ relative = file.relative_to(self.project_root)
102
+ parts = relative.parts
103
+ current = tree
104
+ for part in parts[:-1]:
105
+ if part not in current:
106
+ current[part] = {}
107
+ current = current[part]
108
+
109
+ if '__files__' not in current:
110
+ current['__files__'] = []
111
+ current['__files__'].append(parts[-1])
112
+ except:
113
+ pass
114
+ return tree
115
+
116
+ def _print_tree(self, node: dict, indent: str = "") -> List[str]:
117
+ """Выводит дерево директорий"""
118
+ result = []
119
+ # Сначала директории
120
+ dirs = sorted([k for k in node if k != '__files__'])
121
+ for d in dirs:
122
+ result.append(f"{indent}📁 {d}/")
123
+ result.extend(self._print_tree(node[d], indent + " "))
124
+ # Потом файлы
125
+ if '__files__' in node:
126
+ for f in sorted(node['__files__']):
127
+ result.append(f"{indent}📄 {f}")
128
+ return result
129
+
130
+ def create_file(self, path: str, content: str) -> bool:
131
+ """Создаёт файл"""
132
+ try:
133
+ full_path = self.project_root / path
134
+
135
+ # Создаём директории
136
+ full_path.parent.mkdir(parents=True, exist_ok=True)
137
+
138
+ # Резервная копия если файл существует
139
+ if full_path.exists():
140
+ backup = full_path.with_suffix(full_path.suffix + '.bak')
141
+ shutil.copy2(full_path, backup)
142
+ print_warning(f"📦 Резервная копия: {backup.name}")
143
+
144
+ # Записываем файл
145
+ full_path.write_text(content, encoding='utf-8')
146
+
147
+ lines = content.count('\n') + 1
148
+ size = len(content)
149
+ print_success(f"✅ Создан: {path} ({lines} строк, {size} байт)")
150
+
151
+ return True
152
+ except Exception as e:
153
+ print_error(f"Ошибка создания {path}: {e}")
154
+ return False
155
+
156
+ def modify_file(self, path: str, content: str) -> bool:
157
+ """Изменяет файл"""
158
+ try:
159
+ full_path = self.project_root / path
160
+
161
+ if not full_path.exists():
162
+ print_warning(f"Файл не существует, создаём: {path}")
163
+ return self.create_file(path, content)
164
+
165
+ # Резервная копия
166
+ backup = full_path.with_suffix(full_path.suffix + '.bak')
167
+ shutil.copy2(full_path, backup)
168
+ print_warning(f"📦 Резервная копия: {backup.name}")
169
+
170
+ # Записываем новое содержимое
171
+ full_path.write_text(content, encoding='utf-8')
172
+
173
+ lines = content.count('\n') + 1
174
+ print_success(f"✅ Изменён: {path} ({lines} строк)")
175
+
176
+ return True
177
+ except Exception as e:
178
+ print_error(f"Ошибка изменения {path}: {e}")
179
+ return False
180
+
181
+ def execute_command(self, command: str, timeout: int = 300) -> bool:
182
+ """Выполняет команду"""
183
+ try:
184
+ print_warning(f"\n⚡ Выполнение: {command}")
185
+
186
+ result = subprocess.run(
187
+ command,
188
+ shell=True,
189
+ cwd=self.project_root,
190
+ capture_output=True,
191
+ text=True,
192
+ timeout=timeout
193
+ )
194
+
195
+ if result.stdout:
196
+ print(result.stdout)
197
+
198
+ if result.returncode != 0:
199
+ if result.stderr:
200
+ print_error(result.stderr)
201
+ print_error(f"Команда завершилась с ошибкой (код {result.returncode})")
202
+ return False
203
+
204
+ print_success("✅ Команда выполнена успешно")
205
+ return True
206
+
207
+ except subprocess.TimeoutExpired:
208
+ print_error(f"Таймаут выполнения ({timeout}с)")
209
+ return False
210
+ except Exception as e:
211
+ print_error(f"Ошибка выполнения: {e}")
212
+ return False
213
+
214
+ def save_session(self, history: List[Dict], model: str, stats: Dict) -> str:
215
+ """Сохраняет сессию в файл"""
216
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
217
+ filename = f"handycode_сессия_{timestamp}.md"
218
+
219
+ try:
220
+ with open(filename, 'w', encoding='utf-8') as f:
221
+ f.write(f"# Сессия HandyCode\n\n")
222
+ f.write(f"**Дата:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
223
+ f.write(f"**Модель:** {model}\n")
224
+ f.write(f"**Сообщений:** {stats.get('messages_sent', 0)}\n\n")
225
+ f.write("---\n\n")
226
+
227
+ for msg in history[1:]: # Пропускаем системный промпт
228
+ if msg['role'] == 'user':
229
+ f.write(f"## 👤 Пользователь\n\n{msg['content']}\n\n")
230
+ else:
231
+ clean = msg['content']
232
+ # Убираем маркеры действий для читаемости
233
+ clean = clean.replace('[[CREATE:', '').replace('[[MODIFY:', '').replace('[[EXEC:', '')
234
+ f.write(f"## 🤖 Ассистент\n\n{clean}\n\n---\n\n")
235
+
236
+ return print_success(f"✅ Сессия сохранена: {filename}")
237
+ except Exception as e:
238
+ return print_error(f"Ошибка сохранения: {e}")
handycode/logo.py ADDED
@@ -0,0 +1,90 @@
1
+ """
2
+ Логотип HandyCode для командной строки
3
+ """
4
+
5
+ import sys
6
+ from .utils import Colors, supports_color
7
+
8
+
9
+ def get_logo() -> str:
10
+ """Возвращает ASCII логотип HandyCode"""
11
+ if not supports_color():
12
+ return get_logo_plain()
13
+
14
+ C = Colors
15
+ logo = f"""
16
+ {C.CYAN}{C.BOLD}╔═════════════════════════════════════════════════════════════════════════════════════════════════╗
17
+ ║ ║
18
+ ║ {C.YELLOW}██╗ ██╗{C.CYAN} {C.GREEN}█████╗{C.CYAN} {C.BLUE}███╗ ██╗{C.CYAN} {C.MAGENTA}██████╗{C.CYAN} {C.RED}██╗ ██╗{C.CYAN} {C.WHITE}██████╗{C.CYAN} {C.GREEN}███████╗{C.CYAN} {C.BLUE}██████╗{C.CYAN} {C.MAGENTA}███████╗{C.CYAN} ║
19
+ ║ {C.YELLOW}██║ ██║{C.CYAN} {C.GREEN}██╔══██╗{C.CYAN} {C.BLUE}████╗ ██║{C.CYAN} {C.MAGENTA}██╔══██╗{C.CYAN} {C.RED}╚██╗ ██╔╝{C.CYAN} {C.WHITE}██╔════╝{C.CYAN} {C.GREEN}██╔════██╗{C.CYAN} {C.BLUE}██╔══██╗{C.CYAN} {C.MAGENTA}██╔════╝{C.CYAN} ║
20
+ ║ {C.YELLOW}███████║{C.CYAN} {C.GREEN}███████║{C.CYAN} {C.BLUE}██╔██╗ ██║{C.CYAN} {C.MAGENTA}██║ ██║{C.CYAN} {C.RED}╚████╔╝{C.CYAN} {C.WHITE}██║{C.CYAN} {C.GREEN}██║ ██║{C.CYAN} {C.BLUE}██║ ██║{C.CYAN} {C.MAGENTA}█████╗{C.CYAN} ║
21
+ ║ {C.YELLOW}██╔══██║{C.CYAN} {C.GREEN}██╔══██║{C.CYAN} {C.BLUE}██║╚██╗██║{C.CYAN} {C.MAGENTA}██║ ██║{C.CYAN} {C.RED}╚██╔╝{C.CYAN} {C.WHITE}██║{C.CYAN} {C.GREEN}██║ ██║{C.CYAN} {C.BLUE}██║ ██║{C.CYAN} {C.MAGENTA}██╔══╝{C.CYAN} ║
22
+ ║ {C.YELLOW}██║ ██║{C.CYAN} {C.GREEN}██║ ██║{C.CYAN} {C.BLUE}██║ ╚████║{C.CYAN} {C.MAGENTA}██████╔╝{C.CYAN} {C.RED}██║{C.CYAN} {C.WHITE}╚██████╗{C.CYAN} {C.GREEN}███████╔╝{C.CYAN} {C.BLUE}██████╔╝{C.CYAN} {C.MAGENTA}███████╗{C.CYAN} ║
23
+ ║ {C.YELLOW}╚═╝ ╚═╝{C.CYAN} {C.GREEN}╚═╝ ╚═╝{C.CYAN} {C.BLUE}╚═╝ ╚═══╝{C.CYAN} {C.MAGENTA}╚═════╝{C.CYAN} {C.RED}╚═╝{C.CYAN} {C.WHITE} ╚═════╝{C.CYAN} {C.GREEN}╚═════╝{C.CYAN} {C.BLUE}╚═════╝{C.CYAN} {C.MAGENTA}╚══════╝{C.CYAN} ║
24
+ ║ ║
25
+ ║ {C.WHITE}AI Ассистент для разработки{C.CYAN} ║
26
+ ║ {C.WHITE}Prod. by AURA Tec.{C.CYAN} ║
27
+ ║ ║
28
+ ╚═════════════════════════════════════════════════════════════════════════════════════════════════╝{C.RESET}
29
+ """
30
+ return logo
31
+
32
+
33
+ def get_logo_plain() -> str:
34
+ """Возвращает простой ASCII логотип без цветов"""
35
+ logo = r"""
36
+ ╔══════════════════════════════════════════════════════════════╗
37
+ ║ ║
38
+ ║ ██╗ ██╗ █████╗ ███╗ ██╗ ██████╗ ██╗ ██╗ ║
39
+ ║ ██║ ██║ ██╔══██╗ ████╗ ██║ ██╔══██╗ ╚██╗ ██╔╝ ║
40
+ ║ ███████║ ███████║ ██╔██╗ ██║ ██║ ██║ ╚████╔╝ ║
41
+ ║ ██╔══██║ ██╔══██║ ██║╚██╗██║ ██║ ██║ ╚██╔╝ ║
42
+ ║ ██║ ██║ ██║ ██║ ██║ ╚████║ ██████╔╝ ██║ ║
43
+ ║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ║
44
+ ║ ║
45
+ ║ ██████╗ ███████╗ ██████╗ ███████╗ ║
46
+ ║ ██╔════╝ ██╔════██╗ ██╔══██╗ ██╔════╝ ║
47
+ ║ ██║ ██║ ██║ ██║ ██║ █████╗ ║
48
+ ║ ██║ ██║ ██║ ██║ ██║ ██╔══╝ ║
49
+ ║ ╚██████╗ ███████╔╝ ██████╔╝ ███████╗ ║
50
+ ║ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ║
51
+ ║ ║
52
+ ║ AI Ассистент для разработки ║
53
+ ║ Prod. by AURA Tec. ║
54
+ ║ ║
55
+ ╚══════════════════════════════════════════════════════════════╝
56
+ """
57
+ return logo
58
+
59
+
60
+ def get_small_logo() -> str:
61
+ """Возвращает маленький логотип"""
62
+ if not supports_color():
63
+ return "HandyCode v2.0.0"
64
+
65
+ C = Colors
66
+ return f"{C.CYAN}HandyCode{C.RESET} {C.WHITE}v2.0.0{C.RESET} - {C.GREEN}AI Ассистент{C.RESET}"
67
+
68
+
69
+ def get_install_logo() -> str:
70
+ """Возвращает логотип для установки"""
71
+ if not supports_color():
72
+ return get_logo_plain()
73
+
74
+ C = Colors
75
+ logo = f"""
76
+ {C.CYAN}{C.BOLD}╔═════════════════════════════════════════════════════════════════════════════════════════════════╗
77
+ ║ ║
78
+ ║ {C.YELLOW}██╗ ██╗{C.CYAN} {C.GREEN}█████╗{C.CYAN} {C.BLUE}███╗ ██╗{C.CYAN} {C.MAGENTA}██████╗{C.CYAN} {C.RED}██╗ ██╗{C.CYAN} {C.WHITE}██████╗{C.CYAN} {C.GREEN}███████╗{C.CYAN} {C.BLUE}██████╗{C.CYAN} {C.MAGENTA}███████╗{C.CYAN} ║
79
+ ║ {C.YELLOW}██║ ██║{C.CYAN} {C.GREEN}██╔══██╗{C.CYAN} {C.BLUE}████╗ ██║{C.CYAN} {C.MAGENTA}██╔══██╗{C.CYAN} {C.RED}╚██╗ ██╔╝{C.CYAN} {C.WHITE}██╔════╝{C.CYAN} {C.GREEN}██╔════██╗{C.CYAN} {C.BLUE}██╔══██╗{C.CYAN} {C.MAGENTA}██╔════╝{C.CYAN} ║
80
+ ║ {C.YELLOW}███████║{C.CYAN} {C.GREEN}███████║{C.CYAN} {C.BLUE}██╔██╗ ██║{C.CYAN} {C.MAGENTA}██║ ██║{C.CYAN} {C.RED}╚████╔╝{C.CYAN} {C.WHITE}██║{C.CYAN} {C.GREEN}██║ ██║{C.CYAN} {C.BLUE}██║ ██║{C.CYAN} {C.MAGENTA}█████╗{C.CYAN} ║
81
+ ║ {C.YELLOW}██╔══██║{C.CYAN} {C.GREEN}██╔══██║{C.CYAN} {C.BLUE}██║╚██╗██║{C.CYAN} {C.MAGENTA}██║ ██║{C.CYAN} {C.RED}╚██╔╝{C.CYAN} {C.WHITE}██║{C.CYAN} {C.GREEN}██║ ██║{C.CYAN} {C.BLUE}██║ ██║{C.CYAN} {C.MAGENTA}██╔══╝{C.CYAN} ║
82
+ ║ {C.YELLOW}██║ ██║{C.CYAN} {C.GREEN}██║ ██║{C.CYAN} {C.BLUE}██║ ╚████║{C.CYAN} {C.MAGENTA}██████╔╝{C.CYAN} {C.RED}██║{C.CYAN} {C.WHITE}╚██████╗{C.CYAN} {C.GREEN}███████╔╝{C.CYAN} {C.BLUE}██████╔╝{C.CYAN} {C.MAGENTA}███████╗{C.CYAN} ║
83
+ ║ {C.YELLOW}╚═╝ ╚═╝{C.CYAN} {C.GREEN}╚═╝ ╚═╝{C.CYAN} {C.BLUE}╚═╝ ╚═══╝{C.CYAN} {C.MAGENTA}╚═════╝{C.CYAN} {C.RED}╚═╝{C.CYAN} {C.WHITE} ╚═════╝{C.CYAN} {C.GREEN}╚═════╝{C.CYAN} {C.BLUE}╚═════╝{C.CYAN} {C.MAGENTA}╚══════╝{C.CYAN} ║
84
+ ║ ║
85
+ ║ {C.WHITE}AI Ассистент для разработки{C.CYAN} ║
86
+ ║ {C.WHITE}Prod. by AURA Tec.{C.CYAN} ║
87
+ ║ ║
88
+ ╚═════════════════════════════════════════════════════════════════════════════════════════════════╝{C.RESET}
89
+ """
90
+ return logo
handycode/main.py ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env python3
2
+ """Главная точка входа HandyCode"""
3
+
4
+ import sys
5
+ import os
6
+
7
+ if __package__ is None:
8
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
9
+
10
+ from handycode.cli import main as cli_main
11
+
12
+
13
+ def main():
14
+ """Главная точка входа"""
15
+ try:
16
+ cli_main()
17
+ except KeyboardInterrupt:
18
+ print("\n\n👋 До свидания!")
19
+ sys.exit(0)
20
+ except Exception as e:
21
+ print(f"\n❌ Критическая ошибка: {e}")
22
+ sys.exit(1)
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
handycode/models.py ADDED
@@ -0,0 +1,77 @@
1
+ """
2
+ Конфигурация AI моделей
3
+ """
4
+
5
+ MODELS = {
6
+ # DeepSeek модели
7
+ "deepseek": "deepseek/deepseek-chat",
8
+ "deepseek-coder": "deepseek/deepseek-coder",
9
+ "deepseek-r1": "deepseek/deepseek-r1",
10
+ "deepseek-r1-distill": "deepseek/deepseek-r1-distill-qwen-32b",
11
+
12
+ # OpenAI модели
13
+ "gpt4": "openai/gpt-4-turbo-preview",
14
+ "gpt4o": "openai/gpt-4o",
15
+ "gpt3": "openai/gpt-3.5-turbo",
16
+
17
+ # Anthropic модели
18
+ "claude": "anthropic/claude-3-opus",
19
+ "claude-sonnet": "anthropic/claude-3-sonnet",
20
+ "claude-haiku": "anthropic/claude-3-haiku",
21
+
22
+ # Google модели
23
+ "gemini": "google/gemini-pro",
24
+ "gemini-flash": "google/gemini-flash-1.5",
25
+
26
+ # Meta модели
27
+ "llama": "meta-llama/llama-3-70b-instruct",
28
+ "llama-8b": "meta-llama/llama-3-8b-instruct",
29
+
30
+ # Другие модели
31
+ "mixtral": "mistralai/mixtral-8x7b-instruct",
32
+ "codellama": "codellama/codellama-70b-instruct",
33
+ }
34
+
35
+ MODEL_SETTINGS = {
36
+ "deepseek/deepseek-chat": {
37
+ "temperature": 1,
38
+ "max_tokens": 8000,
39
+ "description": "DeepSeek V3 - Лучший баланс скорости и качества"
40
+ },
41
+ "deepseek/deepseek-coder": {
42
+ "temperature": 1,
43
+ "max_tokens": 8000,
44
+ "description": "DeepSeek Coder - Специализирована для написания кода"
45
+ },
46
+ "deepseek/deepseek-r1": {
47
+ "temperature": 1,
48
+ "max_tokens": 4000,
49
+ "description": "DeepSeek R1 - Глубокое мышление и анализ"
50
+ },
51
+ "openai/gpt-4-turbo-preview": {
52
+ "temperature": 0.3,
53
+ "max_tokens": 4000,
54
+ "description": "GPT-4 Turbo - Мощная универсальная модель"
55
+ },
56
+ "anthropic/claude-3-opus": {
57
+ "temperature": 0.3,
58
+ "max_tokens": 4000,
59
+ "description": "Claude 3 Opus - Продвинутый анализ"
60
+ },
61
+ "anthropic/claude-3-sonnet": {
62
+ "temperature": 0.3,
63
+ "max_tokens": 4000,
64
+ "description": "Claude 3 Sonnet - Быстрая и способная"
65
+ },
66
+ }
67
+
68
+ DEFAULT_SETTINGS = {
69
+ "temperature": 0.3,
70
+ "max_tokens": 4000,
71
+ "description": "Универсальная модель"
72
+ }
73
+
74
+
75
+ def get_model_settings(model_id: str) -> dict:
76
+ """Получает настройки для конкретной модели"""
77
+ return MODEL_SETTINGS.get(model_id, DEFAULT_SETTINGS)
@@ -0,0 +1,55 @@
1
+ """
2
+ Шаблоны проектов для быстрой настройки
3
+ """
4
+
5
+ from typing import Dict
6
+
7
+
8
+ TEMPLATES = {
9
+ 'python': {
10
+ 'description': 'Шаблон Python проекта',
11
+ 'files': {
12
+ 'src/__init__.py': '',
13
+ 'src/main.py': '"""Главный модуль"""\n\n\ndef main():\n print("Привет, Мир!")\n\n\nif __name__ == "__main__":\n main()\n',
14
+ 'tests/__init__.py': '',
15
+ 'tests/test_main.py': '"""Тесты"""\n\nfrom src.main import main\n\n\ndef test_main():\n assert main() is None\n',
16
+ 'requirements.txt': '# Зависимости\n',
17
+ 'README.md': '# Проект\n\n## Установка\n\n```bash\npip install -r requirements.txt\n```\n\n## Запуск\n\n```bash\npython src/main.py\n```\n',
18
+ '.gitignore': '__pycache__/\n*.pyc\n.env\nvenv/\ndist/\n',
19
+ }
20
+ },
21
+ 'react': {
22
+ 'description': 'React с Vite',
23
+ 'files': {
24
+ 'src/App.jsx': 'import React from "react";\n\nexport default function App() {\n return <h1>Привет, Мир!</h1>;\n}\n',
25
+ 'src/main.jsx': 'import React from "react";\nimport ReactDOM from "react-dom/client";\nimport App from "./App";\n\nReactDOM.createRoot(document.getElementById("root")).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>\n);\n',
26
+ 'index.html': '<!DOCTYPE html>\n<html>\n<head>\n <meta charset="UTF-8" />\n <title>React App</title>\n</head>\n<body>\n <div id="root"></div>\n <script type="module" src="/src/main.jsx"></script>\n</body>\n</html>\n',
27
+ 'package.json': '{\n "name": "react-app",\n "version": "1.0.0",\n "scripts": {\n "dev": "vite",\n "build": "vite build"\n },\n "dependencies": {\n "react": "^18.2.0",\n "react-dom": "^18.2.0"\n },\n "devDependencies": {\n "@vitejs/plugin-react": "^4.0.0",\n "vite": "^5.0.0"\n }\n}\n',
28
+ 'vite.config.js': 'import { defineConfig } from "vite";\nimport react from "@vitejs/plugin-react";\n\nexport default defineConfig({\n plugins: [react()]\n});\n',
29
+ '.gitignore': 'node_modules/\ndist/\n',
30
+ }
31
+ },
32
+ 'fastapi': {
33
+ 'description': 'FastAPI проект',
34
+ 'files': {
35
+ 'app/__init__.py': '',
36
+ 'app/main.py': 'from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get("/")\nasync def root():\n return {"message": "Привет, Мир!"}\n',
37
+ 'requirements.txt': 'fastapi\nuvicorn\n',
38
+ 'README.md': '# FastAPI Проект\n\n## Запуск\n\n```bash\nuvicorn app.main:app --reload\n```\n',
39
+ '.gitignore': '__pycache__/\n*.pyc\n.env\nvenv/\n',
40
+ }
41
+ },
42
+ 'node': {
43
+ 'description': 'Node.js с Express',
44
+ 'files': {
45
+ 'src/index.js': 'const express = require("express");\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\n\napp.get("/", (req, res) => {\n res.json({ message: "Привет, Мир!" });\n});\n\napp.listen(PORT, () => {\n console.log(`Сервер: http://localhost:${PORT}`);\n});\n',
46
+ 'package.json': '{\n "name": "node-app",\n "version": "1.0.0",\n "main": "src/index.js",\n "scripts": {\n "start": "node src/index.js"\n },\n "dependencies": {\n "express": "^4.18.0"\n }\n}\n',
47
+ '.gitignore': 'node_modules/\n.env\n',
48
+ }
49
+ }
50
+ }
51
+
52
+
53
+ def get_template(template_name: str) -> Dict:
54
+ """Получает шаблон проекта"""
55
+ return TEMPLATES.get(template_name, {})