Files
G4F/StaticHelper/ai_interface.py
2025-06-02 16:43:01 +03:00

197 lines
9.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 work(self, prompt):
with open("source/header.md", 'r', encoding='utf-8') as file:
header = file.read()
with open("source/docs.md", 'r', encoding='utf-8') as file:
docs = file.read()
with open("source/working_file.md", 'r', encoding='utf-8') as file:
wf = file.read()
try:
log(f"Sending request to AI endpoint with prompt")
messages = [
{"role": "system", "content": header},
{"role": "user", "content": docs},
{"role": "user", "content": prompt+"\n\n"+wf}
]
# Создание запроса к OpenAI
response = self.client.chat.completions.create(
model=DEFAULT_MODEL,
messages=messages,
stream=False,
)
with open("source/old_input.md", 'w', encoding='utf-8') as file:
file.write(wf)
with open("source/working_file.md", 'w', encoding='utf-8') as file:
file.write(response.choices[0].message.content)
log(f"AI response received: {response.choices[0].message.content}")
# Обработка ответа
return {"response": response.choices[0].message.content}
except Exception as e:
log(f"Error communicating with AI endpoint: {e}", level="error")
raise
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.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(
model=DEFAULT_MODEL,
messages=messages,
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, prompt: str, project_structure: dict) -> dict:
"""
Анализирует структуру проекта и запрос пользователя через ИИ.
"""
context = {"project_structure": project_structure}
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> ")
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()