факит

This commit is contained in:
Mikan
2025-06-02 16:43:01 +03:00
parent 4f10dd93c5
commit 6ede1ca15f
13 changed files with 720 additions and 17 deletions

View File

@@ -99,13 +99,17 @@ def run_workflow():
ai_response = ai_interface.analyze_project(user_prompt, full_context)
log(f"AI response: {ai_response}")
# Шаг 5: Генерация плана модификации
command_generator = CommandGenerator()
modifications = ai_response.get("modifications", [])
modification_plan = command_generator.generate_commands(modifications)
ai_response = ai_interface.get_modifications(user_prompt, full_context)
log(f"AI response: {ai_response}")
# # Шаг 5: Генерация плана модификации
# command_generator = CommandGenerator()
# modifications = ai_response.get("modifications", [])
# modification_plan = command_generator.generate_commands(modifications)
with open("modification_plan.md", "w", encoding="utf-8") as f:
f.write(modification_plan)
f.write(ai_response["response"])
log(f"Generated modification plan:\n{modification_plan}")
# log(f"Generated modification plan:\n{modification_plan}")
log("ReactDev workflow completed.")

View File

@@ -2,6 +2,7 @@ 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(
@@ -9,19 +10,24 @@ class AIInterface:
base_url=OPENAI_BASE_URL,
)
def send_request(self, prompt: str, context: dict = None) -> dict:
def send_request(self, prompt: str, context: dict = None, system_prompt: str = "") -> dict:
"""
Отправляет запрос на эндпоинт ИИ через OpenAI и возвращает ответ.
"""
try:
log(f"Sending request to AI endpoint with prompt: {prompt}")
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
# Подготовка сообщений для чат-комплитшена
messages = [{"role": "user", "content": prompt}]
# if context:
# # Преобразуем контекст в строку
# context_str = self._format_context(context)
# messages.append({"role": "system", "content": context_str})
messages.append({"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(
@@ -46,17 +52,107 @@ class AIInterface:
formatted_context.append(f"{key}: {value}")
return "\n".join(formatted_context)
def analyze_project(self, project_structure: str, prompt: str) -> dict:
def analyze_project(self, prompt: str, project_structure: dict) -> dict:
"""
Анализирует структуру проекта и запрос пользователя через ИИ.
"""
context = {"project_structure": project_structure}
return self.send_request(prompt, context)
answer = self.send_request(prompt, context, ANALYZE_PROMPT)
max_attempts = 10
while "Достаточно информации" not in answer.get("response", "Достаточно информации"):
max_attempts -= 1
if max_attempts < 0:
log(f"Error communicating with AI endpoint.", level="error")
raise Exception("Error communicating with AI endpoint.")
for command in answer.get("response", "").split("\n"):
try:
command_type, details = command.split(":", 1)
if command_type.strip().lower() == "запрос содержимого файла":
project_structure['files_info'] = project_structure.get('files_info', {})
try:
with open(details.strip(), "r", encoding="utf-8") as f:
content = f.read()
project_structure['files_info'][details.strip()] = content
except FileNotFoundError:
project_structure['files_info'][details.strip()] = "Файл не найден"
elif command_type.strip().lower() == "запрос содержимого функции":
raise NotImplementedError("Запрос содержимого функции не реализован")
elif command_type.strip().lower() == "уточнение запроса":
answer = self.request_additional_info(details.strip())
project_structure['QA_info'] = project_structure.get('QA_info', {})
project_structure['QA_info'][details.strip()] = answer
else:
raise ValueError(f"Unknown command type: {command_type}")
except Exception as e:
log(f"Error parsing command: {command}", level="error")
answer = self.send_request(prompt, context, ANALYZE_PROMPT)
return answer
def request_additional_info(self, message: str) -> str:
"""
Запрашивает дополнительную информацию у пользователя.
"""
log("Requesting additional information from user.")
return input(f"{message}\n> ")
return input(f"{message}\n> ")
def get_modifications(self, prompt: str, project_structure: dict) -> dict:
"""
Создает модификации проекта на основе команды пользователя.
"""
context = {"project_structure": project_structure}
answer = self.send_request(prompt, context, COMMANDS_PROMPT)
return answer
ANALYZE_PROMPT = """
Ты - эксперт по анализу структуры проектов.
Ты должен проанализировать структуру проекта и запрос пользователя.
Если данных которые тебе передали достаточно - ответь "Достаточно информации".
Если данных недостаточно - запроси содержимое файла или функции которые тебе интересны и/или запроси у пользователя дополнительную информацию.
Если не получается найти файл или функцию - учитывай что его возможно нужно будет создать и ты можешь пропустить этот шаг и продолжить работу дальше. Пути должны соответствовать структуре проекта.
ОТВЕЧАЙ ТОЛЬКО КОМАНДАМИ!
### Запрос содержимого файла
Содержимое файла: <имя файла>
### Запрос содержимого функции
Содержимое функции: <имя файла> <имя функции>
### Запрос у пользователя
Уточнение запроса: <текст вопроса к пользователю>
Например, вот ответ с двумя командами, первый просить содержимое файла, второй - уточнить что нужно создать.:
Содержимое файла: app/models/user.ts
Уточнение запроса: Нужно ли создать интерфейсы в types/users.ts?
НЕ ОТВЕЧАЙ НИЧЕМ ЧТО НЕ СООТВЕТСТВУЕТ ПРАВИЛАМ ВЫШЕ, ТОЛЬКО КОМАНДЫ!
ПОСТАРАЙСЯ В ОДНОМ ОТВЕТЕ НАПИСАТЬ ВСЕ НЕОБХОДИМЫЕ КОМАНДЫ!
""".strip()
COMMANDS_PROMPT = """
Ты - senior developer. Ты должен прочитать запрос пользователя и на его основе сформировать список команд для выполнения этого запроса.
Ты должен ознакомиться с текущей структурой проекта и отдельными файлами и функциями.
Итого ты должен сформировать список команд для выполнения этого запроса.
Команды в таком формате через перенос строки:
`FILE <Команда>` `<имя и путь к файлу>`
`FUNCTION <Команда>` `<имя функции>`
```ts
<код функции>
```
Команды: CREATE, UPDATE, DELETE
НЕ ОТВЕЧАЙ НИЧЕМ ЧТО НЕ СООТВЕТСТВУЕТ ПРАВИЛАМ ВЫШЕ, ТОЛЬКО КОМАНДЫ!
ПОСТАРАЙСЯ В ОДНОМ ОТВЕТЕ НАПИСАТЬ ВСЕ НЕОБХОДИМЫЕ КОМАНДЫ!
""".strip()

View File

@@ -5,16 +5,19 @@ from pathspec import PathSpec
from pathspec.patterns import GitWildMatchPattern
from ..utils.logger import log
from .file_analyzer import FileAnalyzer
class ProjectMap:
def __init__(self, project_path: str):
self.project_path = project_path
self.gitignore_rules = self._load_gitignore()
self.file_analyzer = FileAnalyzer()
def generate_map(self) -> str:
"""
Создает карту структуры проекта, игнорируя файлы из .gitignore и директорию .git/.
Добавляет информацию о функциях в файлы .ts, .tsx, .js, .jsx.
"""
log("Generating project structure map...")
structure = self._traverse_directory(self.project_path)
@@ -44,6 +47,15 @@ class ProjectMap:
result += self._traverse_directory(full_path, level + 1)
else:
result += f"{indent}- {entry}\n"
# Если это файл TypeScript/JavaScript, добавляем информацию о функциях
if entry.endswith((".ts", ".tsx", ".js", ".jsx")):
functions_info = self.file_analyzer.analyze_file(full_path)
if functions_info:
for func_name, details in functions_info.items():
params = ", ".join(details["params"])
return_type = details.get("return_type", "unknown")
result += f"{indent} FUNCTION {func_name}({params}): {return_type}\n"
return result
def save_map(self, output_file: str = "react_app_map.txt"):
@@ -78,4 +90,4 @@ class ProjectMap:
spec = PathSpec.from_lines(GitWildMatchPattern, self.gitignore_rules)
# Проверяем, соответствует ли путь правилам
return spec.match_file(path)
return spec.match_file(path)