This commit is contained in:
Mikan
2025-06-02 14:16:03 +03:00
commit 83cfcd9fb1
19 changed files with 430 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
from openai import OpenAI
from ..config import OPENAI_API_KEY, OPENAI_BASE_URL, DEFAULT_MODEL
from ..utils.logger import log
class AIInterface:
def __init__(self):
self.client = OpenAI(
api_key=OPENAI_API_KEY,
base_url=OPENAI_BASE_URL,
)
def send_request(self, prompt: str, context: dict = None) -> dict:
"""
Отправляет запрос на эндпоинт ИИ через OpenAI и возвращает ответ.
"""
try:
log(f"Sending request to AI endpoint with prompt: {prompt}")
# Подготовка сообщений для чат-комплитшена
messages = [{"role": "user", "content": prompt}]
if context:
# Преобразуем контекст в строку
context_str = self._format_context(context)
messages.append({"role": "system", "content": context_str})
# Создание запроса к OpenAI
response = self.client.chat.completions.create(
model=DEFAULT_MODEL,
messages=[{"role": "user", "content": "Write a poem about a tree"}],
stream=False, # Пока отключаем стриминг для простоты
)
# Обработка ответа
return {"response": response.choices[0].message.content}
except Exception as e:
log(f"Error communicating with AI endpoint: {e}", level="error")
raise
def _format_context(self, context: dict) -> str:
"""
Преобразует контекст в строку для передачи в OpenAI API.
"""
formatted_context = []
for key, value in context.items():
formatted_context.append(f"{key}: {value}")
return "\n".join(formatted_context)
def analyze_project(self, project_structure: str, prompt: str) -> dict:
"""
Анализирует структуру проекта и запрос пользователя через ИИ.
"""
context = {"project_structure": project_structure}
return self.send_request(prompt, context)
def request_additional_info(self, message: str) -> str:
"""
Запрашивает дополнительную информацию у пользователя.
"""
log("Requesting additional information from user.")
return input(f"{message}\n> ")

26
ReactDev/core/commands.py Normal file
View File

@@ -0,0 +1,26 @@
from ..utils.logger import log
class CommandGenerator:
def __init__(self):
pass
def generate_commands(self, modifications: list) -> str:
"""
Генерирует план модификации на основе анализа ИИ.
"""
log("Generating modification plan...")
commands = []
for mod in modifications:
action = mod.get("action")
file = mod.get("file")
function = mod.get("function")
code = mod.get("code", "")
if action == "CREATE":
commands.append(f"CREATE {function} {file}")
elif action == "DELETE":
commands.append(f"DELETE {function} {file}")
elif action == "MODIFY":
commands.append(f"MODIFY {function} {file}")
commands.append(f"```ts\n{code}\n```")
return "\n".join(commands)

View File

@@ -0,0 +1,37 @@
import esprima
from ..utils.logger import log
class FileAnalyzer:
def __init__(self):
pass
def analyze_file(self, file_path: str) -> dict:
"""
Анализирует файл и извлекает информацию о функциях.
"""
log(f"Analyzing file: {file_path}")
with open(file_path, "r") as f:
code = f.read()
try:
parsed = esprima.parseScript(code, loc=True)
functions = self._extract_functions(parsed)
return functions
except Exception as e:
log(f"Error parsing file {file_path}: {e}", level="error")
return {}
def _extract_functions(self, ast: dict) -> dict:
"""
Извлекает информацию о функциях из AST.
"""
functions = {}
for node in ast.body:
if node.type == "FunctionDeclaration":
name = node.id.name
params = [param.name for param in node.params]
functions[name] = {
"params": params,
"return_type": "unknown", # Тип возвращаемого значения не всегда доступен
}
return functions

View File

@@ -0,0 +1,81 @@
import os
from pathlib import Path
from pathspec import PathSpec
from pathspec.patterns import GitWildMatchPattern
from ..utils.logger import log
class ProjectMap:
def __init__(self, project_path: str):
self.project_path = project_path
self.gitignore_rules = self._load_gitignore()
def generate_map(self) -> str:
"""
Создает карту структуры проекта, игнорируя файлы из .gitignore и директорию .git/.
"""
log("Generating project structure map...")
structure = self._traverse_directory(self.project_path)
return structure
def _traverse_directory(self, path: str, level: int = 0) -> str:
"""
Рекурсивно обходит директории и формирует строку структуры,
игнорируя файлы и директории из .gitignore и .git/.
"""
indent = " " * level
result = ""
for entry in sorted(os.listdir(path)):
full_path = os.path.join(path, entry)
# Игнорируем директорию .git/
if entry == ".git":
continue
# Проверяем, игнорируется ли файл или директория по правилам .gitignore
relative_path = os.path.relpath(full_path, self.project_path)
if self._is_ignored(relative_path):
continue
if os.path.isdir(full_path):
result += f"{indent}- {entry}/\n"
result += self._traverse_directory(full_path, level + 1)
else:
result += f"{indent}- {entry}\n"
return result
def save_map(self, output_file: str = "react_app_map.txt"):
"""
Сохраняет карту структуры в файл.
"""
map_content = self.generate_map()
with open(output_file, "w") as f:
f.write(map_content)
log(f"Project map saved to {output_file}")
def _load_gitignore(self) -> list:
"""
Загружает правила из .gitignore, если файл существует.
"""
gitignore_path = os.path.join(self.project_path, ".gitignore")
rules = []
if os.path.exists(gitignore_path):
with open(gitignore_path, "r") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#"): # Игнорируем комментарии и пустые строки
rules.append(line)
return rules
def _is_ignored(self, path: str) -> bool:
"""
Проверяет, игнорируется ли файл или директория по правилам .gitignore,
включая поддержку сложных правил (например, **/logs/*.log).
"""
# Преобразуем правила .gitignore в PathSpec
spec = PathSpec.from_lines(GitWildMatchPattern, self.gitignore_rules)
# Проверяем, соответствует ли путь правилам
return spec.match_file(path)