initial
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/react_app_map.txt
|
||||||
|
/instructions.md
|
||||||
|
/prompt.md
|
||||||
|
/workingon.md
|
||||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
13
.idea/G4F.iml
generated
Normal file
13
.idea/G4F.iml
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PackageRequirementsSettings">
|
||||||
|
<option name="keepMatchingSpecifier" value="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.12 (G4F)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (G4F)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/G4F.iml" filepath="$PROJECT_DIR$/.idea/G4F.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
111
ReactDev/__init__.py
Normal file
111
ReactDev/__init__.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Инициализация пакета
|
||||||
|
import os
|
||||||
|
|
||||||
|
from .core.ai_interface import AIInterface
|
||||||
|
from .core.project_map import ProjectMap
|
||||||
|
from .core.file_analyzer import FileAnalyzer
|
||||||
|
from .core.commands import CommandGenerator
|
||||||
|
from .utils.logger import log
|
||||||
|
from .utils.file_utils import read_file, write_file
|
||||||
|
from .config import REACT_PROJECT_PATH
|
||||||
|
|
||||||
|
__all__ = ["AIInterface", "ProjectMap", "FileAnalyzer", "CommandGenerator", "run_workflow"]
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_default_files():
|
||||||
|
"""
|
||||||
|
Проверяет наличие необходимых файлов и создает их с базовым содержимым, если они отсутствуют.
|
||||||
|
"""
|
||||||
|
default_files = {
|
||||||
|
"workingon.md": "/path/to/react/project/src/Auth.tsx",
|
||||||
|
"prompt.md": "Добавить функцию авторизации в файл Auth.tsx",
|
||||||
|
"instructions.md": "# Инструкции для ИИ\n\n1. Функции должны быть написаны в TypeScript.\n2. Используйте современные практики React (например, хуки).\n3. При создании новых компонентов добавьте комментарии.",
|
||||||
|
}
|
||||||
|
|
||||||
|
for file_name, content in default_files.items():
|
||||||
|
if not os.path.exists(file_name):
|
||||||
|
log(f"File {file_name} not found. Creating it with default content.")
|
||||||
|
write_file(file_name, content)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_workingon_content(content: str) -> dict:
|
||||||
|
"""
|
||||||
|
Парсит содержимое файла workingon.md.
|
||||||
|
Возвращает словарь с путем к файлу и дополнительным контекстом.
|
||||||
|
"""
|
||||||
|
lines = content.strip().split("\n")
|
||||||
|
result = {"file_path": None, "context": ""}
|
||||||
|
|
||||||
|
if lines:
|
||||||
|
# Первая строка — путь к файлу
|
||||||
|
result["file_path"] = lines[0].strip()
|
||||||
|
# Остальные строки — дополнительный контекст
|
||||||
|
result["context"] = "\n".join(lines[1:]).strip()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def run_workflow():
|
||||||
|
"""
|
||||||
|
Основной алгоритм работы библиотеки ReactDev.
|
||||||
|
1. Создает карту структуры проекта.
|
||||||
|
2. Анализирует файлы на наличие функций.
|
||||||
|
3. Отправляет запрос к ИИ с контекстом.
|
||||||
|
4. Генерирует план модификации.
|
||||||
|
"""
|
||||||
|
log("Starting ReactDev workflow...")
|
||||||
|
|
||||||
|
# Шаг 0: Убедиться, что все необходимые файлы существуют
|
||||||
|
ensure_default_files()
|
||||||
|
|
||||||
|
# Шаг 1: Создание карты структуры проекта
|
||||||
|
project_map = ProjectMap(REACT_PROJECT_PATH)
|
||||||
|
project_structure = project_map.generate_map()
|
||||||
|
project_map.save_map()
|
||||||
|
|
||||||
|
log(f"Generated project structure:\n{project_structure}")
|
||||||
|
|
||||||
|
# Шаг 2: Чтение и парсинг workingon.md
|
||||||
|
workingon_content = read_file("workingon.md")
|
||||||
|
workingon_data = parse_workingon_content(workingon_content)
|
||||||
|
|
||||||
|
target_file = workingon_data["file_path"]
|
||||||
|
additional_context = workingon_data["context"]
|
||||||
|
|
||||||
|
if target_file and not os.path.exists(target_file):
|
||||||
|
log(f"Target file {target_file} does not exist.", level="error")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Шаг 3: Анализ целевого файла (если указан)
|
||||||
|
functions_info = {}
|
||||||
|
if target_file:
|
||||||
|
file_analyzer = FileAnalyzer()
|
||||||
|
functions_info = file_analyzer.analyze_file(target_file)
|
||||||
|
log(f"Analyzed functions in {target_file}: {functions_info}")
|
||||||
|
|
||||||
|
# Шаг 4: Отправка запроса к ИИ
|
||||||
|
ai_interface = AIInterface()
|
||||||
|
user_prompt = read_file("prompt.md").strip()
|
||||||
|
|
||||||
|
# Добавляем дополнительный контекст из workingon.md
|
||||||
|
full_context = {
|
||||||
|
"project_structure": project_structure,
|
||||||
|
"target_file": target_file,
|
||||||
|
"functions_info": functions_info,
|
||||||
|
"additional_context": additional_context,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
with open("modification_plan.md", "w") as f:
|
||||||
|
f.write(modification_plan)
|
||||||
|
|
||||||
|
log(f"Generated modification plan:\n{modification_plan}")
|
||||||
|
log("ReactDev workflow completed.")
|
||||||
4
ReactDev/config.py
Normal file
4
ReactDev/config.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
REACT_PROJECT_PATH = r'C:\Users\Mikan\PycharmProjects\tisbiProFi\frontend\react-source'
|
||||||
|
OPENAI_API_KEY = "secret" # Замените на ваш API-ключ
|
||||||
|
OPENAI_BASE_URL = "http://localhost:51337/v1" # Базовый URL для OpenAI
|
||||||
|
DEFAULT_MODEL = "gpt-4o-mini" # Модель по умолчанию
|
||||||
62
ReactDev/core/ai_interface.py
Normal file
62
ReactDev/core/ai_interface.py
Normal 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
26
ReactDev/core/commands.py
Normal 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)
|
||||||
37
ReactDev/core/file_analyzer.py
Normal file
37
ReactDev/core/file_analyzer.py
Normal 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
|
||||||
81
ReactDev/core/project_map.py
Normal file
81
ReactDev/core/project_map.py
Normal 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)
|
||||||
9
ReactDev/examples/instructions.md
Normal file
9
ReactDev/examples/instructions.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
1. Компоненты должны быть функциональными и писаться в формате
|
||||||
|
```tsx
|
||||||
|
function Component({a}:{a:type}){
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
2. Функции должны быть написаны в TypeScript.
|
||||||
|
3. Используйте современные практики React (например, хуки).
|
||||||
|
4. При создании новых компонентов добавьте комментарии.
|
||||||
21
ReactDev/utils/file_utils.py
Normal file
21
ReactDev/utils/file_utils.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
def read_file(file_path: str) -> str:
|
||||||
|
"""
|
||||||
|
Читает содержимое файла.
|
||||||
|
"""
|
||||||
|
with open(file_path, "r") as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
def write_file(file_path: str, content: str):
|
||||||
|
"""
|
||||||
|
Записывает содержимое в файл.
|
||||||
|
"""
|
||||||
|
with open(file_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
def create_directory(path: str):
|
||||||
|
"""
|
||||||
|
Создает директорию, если она не существует.
|
||||||
|
"""
|
||||||
|
os.makedirs(path, exist_ok=True)
|
||||||
13
ReactDev/utils/logger.py
Normal file
13
ReactDev/utils/logger.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
def log(message: str, level: str = "info"):
|
||||||
|
"""
|
||||||
|
Логирует сообщения в консоль.
|
||||||
|
"""
|
||||||
|
levels = {
|
||||||
|
"info": "[INFO]",
|
||||||
|
"warning": "[WARNING]",
|
||||||
|
"error": "[ERROR]",
|
||||||
|
}
|
||||||
|
prefix = levels.get(level, "[UNKNOWN]")
|
||||||
|
print(f"{prefix} {message}", file=sys.stderr if level == "error" else sys.stdout)
|
||||||
0
ReactDev/utils/prompt_utils.py
Normal file
0
ReactDev/utils/prompt_utils.py
Normal file
10
main.py
Normal file
10
main.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# This is a sample Python script.
|
||||||
|
import ReactDev
|
||||||
|
|
||||||
|
# Press Shift+F10 to execute it or replace it with your code.
|
||||||
|
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ReactDev.run_workflow()
|
||||||
|
|
||||||
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
requests~=2.32.3
|
||||||
|
esprima~=4.0.1
|
||||||
|
pathspec~=0.12.1
|
||||||
|
openai~=1.82.1
|
||||||
Reference in New Issue
Block a user