|
import openai |
|
from openai import OpenAI |
|
import difflib |
|
|
|
prompt_check_error_message = """ |
|
Ты — лингвистический анализатор. Тебе будут дано описание ошибки в тексте. |
|
|
|
Задача: |
|
- Если в сообщении говорится что ошибки нет или что это ошибка форматирования - верни 0 |
|
- В остальных случаях возвращай 1 |
|
|
|
Обрати внимаение, если ты бы охарактеризовал ошибку в тексте, как ошибку форматирования или оформления, то нужно вернуть 0!!! |
|
|
|
Сообщение об ошибке: |
|
{} |
|
|
|
Вывод В ФОРМАТЕ JSON без комментариев: |
|
{{"result": 0|1}} |
|
""" |
|
|
|
prompt_is_there_error = """ |
|
Ты — лингвистический анализатор. Тебе будут даны две текстовые строки: |
|
1. Оригинальный текст (точно без ошибок) |
|
2. Текст для проверки (может содержать ошибку или альтернативное написание) |
|
|
|
Задача: |
|
- Сравни второй текст с оригиналом на предмет наличия ошибок (орфографических, пунктуационных, грамматических) |
|
- Если во втором тексте есть орфографическая, пунктуационная или грамматическая ошибка(отличается от оригинала и это не допустимый вариант написания) — верни 1 |
|
- Если текст совпадает с оригиналом или отличается только допустимыми вариантами написания (синонимы, альтернативная пунктуация и т.п.) или же присутствует ошибка формативарования — верни 0 |
|
|
|
Обрати внимаение, если ты бы охарактеризовал ошибку в тексте, как ошибку форматирования или оформления, то нужно вернуть 0!!! |
|
|
|
Оригинальный текст: |
|
{} |
|
|
|
Текст для проверки: |
|
{} |
|
|
|
Вывод В ФОРМАТЕ JSON без комментариев: |
|
{{"result": 0|1}} |
|
""" |
|
|
|
prompt_fix_text_gpt = """ |
|
Исправь ошибки в данном тексте. Текст в makrdown и должен в результате остаться в markdown. |
|
Исправляй грамматические, пунктуационные и орфоргафические ошибки. |
|
Логические, лексические, стилистические ошибки, а также ошибки форматирования (напрмер неправильные переносы строки) ошибками не считаются!!! Их исправлять не надо |
|
Буква "е" вместо буквы "ё" не считается ошибкой. |
|
Не исправляй ошибки форматрирования!!! В текст заранее удалены все ненужны переносы, это сделано осознанно! |
|
Верни только текст, никаких комментариев от себя не оставляй. |
|
|
|
### Пример 1: |
|
input text: |
|
Это все мое, чашки вилки и ложи |
|
|
|
Твой ответ: |
|
Это все мое: чашки, вилки и ложки |
|
|
|
|
|
Теперь твоя очередь: |
|
input text: |
|
{} |
|
""" |
|
|
|
prompt_compare_get_comment = """ |
|
Ты должен писать комментарий об ошибке в тексте. |
|
Тебе дан кусок текст, в котором есть одна или несколько ошибок и этот же кусок текста с исправленными ошибками. |
|
Твоя задача - кратко описать все ошибки, которые есть в тексте. |
|
Пиши кратко, не больше одного-двух предложений. Отвечай на русском языке. |
|
|
|
|
|
### Пример 1: |
|
original text: |
|
"кросивую, сабаку" |
|
|
|
corrected text: |
|
"красивую собаку" |
|
|
|
Твой ответ: |
|
Орфографические ошибки: "кросивую" -> "красивую", "сабаку" -> "собаку", лишняя запятая после "красивую". |
|
|
|
|
|
### Пример 2: |
|
original: |
|
"я решил пойти, в" |
|
|
|
corrected text: |
|
"я решил пойти в" |
|
|
|
Твой ответ: |
|
Опечатка: повтор пробела, лишняя запятая после слова "пойти". |
|
|
|
|
|
Теперь твоя очередь: |
|
original: |
|
"{}" |
|
|
|
corrected text: |
|
"{}" |
|
""" |
|
|
|
prompt = """ |
|
Ты должен писать комментарии об ошибках в тексте. |
|
Тебе дан кусок текст, в котором есть ошибка, контекст, в котором стоит это слово и сообщение об ошибке. Твоя задача - кратко описать суть ошибки и, если необходимо, исправить её. |
|
Исправляй только ту ошибку, на которую указывает сообщение. Отвечай на русском языке. |
|
|
|
### Пример 1: |
|
Кусок текста: |
|
"кросивую" |
|
|
|
Сообщение об ошибке: |
|
"Возможно найдена орфографическая ошибка." |
|
|
|
Текст: |
|
"...т! Сегодня я был в парке и встретил там кросивую собаку. Она повиляла хвостом и побежа..." |
|
|
|
Твой ответ: |
|
Орфографическая ошибка в слове "кросивую" - правильно "красивую". |
|
|
|
### Пример 2: |
|
Кусок текста: |
|
" " |
|
|
|
Сообщение об ошибке: |
|
"Повтор пробела." |
|
|
|
Текст: |
|
"...ретил там кросивую собаку. Она повиляла хвостом и побежала к речке. Я решил что ..." |
|
|
|
Твой ответ: |
|
Обнаружен повтор пробела между словами. |
|
|
|
Теперь твоя очередь: |
|
Кусок текста: |
|
"{}" |
|
|
|
Сообщение об ошибке: |
|
"{}" |
|
|
|
Текст: |
|
"{}" |
|
""" |
|
|
|
|
|
def get_gpt_response_openai(inp): |
|
response = openai.ChatCompletion.create( |
|
model="openai/gpt-4.1-mini", |
|
messages=[ |
|
{"role": "user", "content": inp} |
|
] |
|
) |
|
return response.choices[0].message['content'] |
|
|
|
|
|
def get_gpt_response_vsegpt(inp): |
|
client = OpenAI( |
|
api_key='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', |
|
base_url='https://openrouter.ai/api/v1' |
|
) |
|
response = client.chat.completions.create( |
|
model="openai/gpt-4.1-mini", |
|
messages=[{"role": "user", "content": inp}] |
|
).choices[0].message.content |
|
|
|
return response |
|
|
|
|
|
def get_gpt_response(inp, client_name="vsegpt"): |
|
if client_name == "openai": |
|
return get_gpt_response_openai(inp) |
|
elif client_name == "vsegpt": |
|
return get_gpt_response_vsegpt(inp) |
|
else: |
|
raise ValueError(f"Unsupported client: {client_name}") |
|
|
|
|
|
def find_corrected_positions(original, corrected): |
|
matcher = difflib.SequenceMatcher(None, original, corrected) |
|
changes = [] |
|
|
|
for opcode in matcher.get_opcodes(): |
|
tag, i1, i2, j1, j2 = opcode |
|
if tag != 'equal': |
|
changes.append({ |
|
'original': (i1, i2), |
|
'corrected': (j1, j2), |
|
'operation': tag |
|
}) |
|
|
|
return changes |
|
|
|
|
|
def get_piece_of_text_bounds(s, start, end): |
|
if start != 0: start -= 1 |
|
while start != 0 and s[start] not in [' ', "\n", '\t']: |
|
start -= 1 |
|
if s[start] in [' ', "\n", '\t']: start += 1 |
|
|
|
if end < len(s) - 1: end += 1 |
|
while end < len(s) - 1 and s[end] not in [' ', "\n", '\t']: |
|
end += 1 |
|
if end == len(s) - 1: end += 1 |
|
return start, end |
|
|
|
|
|
def add_comments_to_text(text, errors, add_errors=False): |
|
errors = sorted(errors, key=lambda x: x['end']) |
|
|
|
shift = 0 |
|
for i, error in enumerate(errors, 1): |
|
error['start'] += shift |
|
error['end'] += shift |
|
inp = f"({i})" |
|
|
|
end_place = error["end"] |
|
for i in range(end_place, end_place - 5, -1): |
|
symbol = text[i - 1] |
|
if symbol.isalpha() or symbol in ",.!?:;": |
|
break |
|
error["end"] -= 1 |
|
if add_errors: |
|
inp = inp[:-1] + ' - ' + error['message'] + ')' |
|
text = text[:error['end']] + inp + text[error['end']:] |
|
error["end"] += len(inp) |
|
shift += len(inp) |
|
|
|
return text |
|
|
|
|
|
def check_text(text, tool, mode="chat_gpt", highlight_mode=False, add_errors=False): |
|
if mode == "tool": |
|
return check_text_with_tool(text, tool, add_errors=add_errors) |
|
else: |
|
if highlight_mode: |
|
return check_text_chat_gpt_highlight_mode(text, add_errors=add_errors) |
|
else: |
|
return check_text_chat_gpt(text, add_errors=add_errors) |
|
|
|
|
|
def check_text_chat_gpt(text, fixed_text=None, add_errors=False, *args, **kwargs): |
|
if fixed_text is None: |
|
fixed_text = get_gpt_response(prompt_fix_text_gpt.format(text), "vsegpt") |
|
changes = find_corrected_positions(text, fixed_text) |
|
errors = [] |
|
|
|
for change in changes: |
|
start_orig, end_orig = get_piece_of_text_bounds(text, change['original'][0], change['original'][1]) |
|
start_corr, end_corr = get_piece_of_text_bounds(fixed_text, change['corrected'][0], change['corrected'][1]) |
|
inp = prompt_compare_get_comment.format(text[start_orig:end_orig], fixed_text[start_corr:end_corr]) |
|
errors.append({ |
|
'start': start_orig, |
|
'end': end_orig, |
|
'message': get_gpt_response(inp, client_name="vsegpt"), |
|
}) |
|
|
|
text_with_comments = add_comments_to_text(text, errors, add_errors=add_errors) |
|
return text_with_comments, errors |
|
|
|
|
|
def check_text_chat_gpt_highlight_mode(text, fixed_text=None, add_errors=False, *args, **kwargs): |
|
if fixed_text is None: |
|
fixed_text = get_gpt_response(prompt_fix_text_gpt.format(text), "vsegpt") |
|
|
|
text = text.replace("ё", "е") |
|
fixed_text = fixed_text.replace("ё", "е") |
|
|
|
changes = find_corrected_positions(text, fixed_text) |
|
bounds_init = [] |
|
for change in changes: |
|
start_orig, end_orig = get_piece_of_text_bounds(text, change['original'][0], change['original'][1]) |
|
start_corr, end_corr = get_piece_of_text_bounds(fixed_text, change['corrected'][0], change['corrected'][1]) |
|
bounds_init.append({"start_orig": start_orig, |
|
"end_orig": end_orig, |
|
"start_corr": start_corr, |
|
"end_corr": end_corr}) |
|
|
|
bounds_init = sorted(bounds_init, key=lambda x: x["start_orig"]) |
|
bounds_result = [bounds_init[0]] if len(bounds_init) > 0 else [] |
|
for bound in bounds_init[1:]: |
|
if bounds_result[-1]["end_orig"] >= bound["start_orig"]: |
|
bounds_result[-1]["end_orig"] = max(bounds_result[-1]["end_orig"], bound["end_orig"]) |
|
bounds_result[-1]["end_corr"] = max(bounds_result[-1]["end_corr"], bound["end_corr"]) |
|
else: |
|
bounds_result.append(bound.copy()) |
|
|
|
errors = [] |
|
for bound in bounds_result: |
|
orig_piece = text[bound["start_orig"]:bound["end_orig"]] |
|
fixed_piece = fixed_text[bound["start_corr"]:bound["end_corr"]] |
|
if "0" in get_gpt_response(prompt_is_there_error.format(orig_piece, fixed_piece)): |
|
continue |
|
inp = prompt_compare_get_comment.format(orig_piece, fixed_piece) |
|
error = { |
|
'start': bound["start_orig"], |
|
'end': bound["end_orig"], |
|
'message': get_gpt_response(inp, client_name="vsegpt"), |
|
} |
|
|
|
errors.append(error) |
|
|
|
text_with_comments = add_comments_to_text(text, errors, add_errors=add_errors) |
|
return text_with_comments, errors |
|
|
|
|
|
def check_text_with_tool(text, tool, add_errors=False): |
|
matches = tool.check(text) |
|
errors = [] |
|
for match in matches: |
|
inp = prompt.format(text[match.offset:match.offset + match.errorLength], |
|
match.message, match.context) |
|
error_info = { |
|
'start': match.offset, |
|
'end': match.offset + match.errorLength, |
|
'message': get_gpt_response(inp, client_name="vsegpt"), |
|
} |
|
errors.append(error_info) |
|
|
|
text_with_comments = add_comments_to_text(text, errors, add_errors=add_errors) |
|
return text_with_comments, errors |
|
|