init
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
# 🔧 Исправление: Экранирование HTML тегов в комментариях
|
||||
|
||||
## 🐛 Проблема
|
||||
|
||||
AI комментарии содержали упоминания JSX/HTML тегов, которые **исчезали** при отображении в Gitea/GitHub:
|
||||
|
||||
**До исправления:**
|
||||
```
|
||||
Неправильное использование key: key должен быть на элементе , а не на
|
||||
↑ ↑
|
||||
<CharacterItem> исчез <img> исчез
|
||||
```
|
||||
|
||||
**Причина:** Markdown интерпретирует `<CharacterItem>` как HTML тег и пытается его отрендерить, но т.к. такого тега не существует, он просто исчезает.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Решение
|
||||
|
||||
Добавлена функция **`_escape_html_in_text()`**, которая **оборачивает HTML-подобные теги** в backticks:
|
||||
|
||||
```python
|
||||
def _escape_html_in_text(self, text: str) -> str:
|
||||
"""Escape HTML tags in text to prevent Markdown from hiding them"""
|
||||
import re
|
||||
|
||||
def replace_tag(match):
|
||||
tag = match.group(0)
|
||||
return f"`{tag}`" # Оборачиваем в backticks
|
||||
|
||||
# Находим все <...> паттерны
|
||||
text = re.sub(r'<[^>]+>', replace_tag, text)
|
||||
return text
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Как работает
|
||||
|
||||
### Шаг 1: AI генерирует комментарий
|
||||
|
||||
```
|
||||
"key должен быть на элементе <CharacterItem>, а не на <img>"
|
||||
```
|
||||
|
||||
### Шаг 2: Функция экранирования
|
||||
|
||||
```python
|
||||
text = _escape_html_in_text(text)
|
||||
# Результат:
|
||||
"key должен быть на элементе `<CharacterItem>`, а не на `<img>`"
|
||||
```
|
||||
|
||||
### Шаг 3: В Gitea/GitHub отображается
|
||||
|
||||
```
|
||||
key должен быть на элементе `<CharacterItem>`, а не на `<img>`
|
||||
↑ ↑ ↑ ↑
|
||||
backticks делают теги видимыми
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Примеры
|
||||
|
||||
### Пример 1: JSX элементы
|
||||
|
||||
**Входной текст:**
|
||||
```
|
||||
Неправильное использование key: key должен быть на <CharacterItem>, а не на <img>
|
||||
```
|
||||
|
||||
**После обработки:**
|
||||
```
|
||||
Неправильное использование key: key должен быть на `<CharacterItem>`, а не на `<img>`
|
||||
```
|
||||
|
||||
**В Gitea видно:**
|
||||
```
|
||||
Неправильное использование key: key должен быть на `<CharacterItem>`, а не на `<img>`
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Пример 2: HTML теги
|
||||
|
||||
**Входной текст:**
|
||||
```
|
||||
Используйте <div> вместо <span> для обертки
|
||||
```
|
||||
|
||||
**После обработки:**
|
||||
```
|
||||
Используйте `<div>` вместо `<span>` для обертки
|
||||
```
|
||||
|
||||
**В Gitea видно:**
|
||||
```
|
||||
Используйте `<div>` вместо `<span>` для обертки
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Пример 3: Без HTML тегов
|
||||
|
||||
**Входной текст:**
|
||||
```
|
||||
Опечатка в строке: 'shmapplication/json' должно быть 'application/json'
|
||||
```
|
||||
|
||||
**После обработки:**
|
||||
```
|
||||
Опечатка в строке: 'shmapplication/json' должно быть 'application/json'
|
||||
```
|
||||
|
||||
**В Gitea видно:**
|
||||
```
|
||||
Опечатка в строке: 'shmapplication/json' должно быть 'application/json'
|
||||
```
|
||||
|
||||
*Без изменений - теги не найдены*
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Где применяется
|
||||
|
||||
Функция вызывается **дважды** для каждого ревью:
|
||||
|
||||
### 1. Для каждого комментария
|
||||
|
||||
```python
|
||||
for comment_data in state["comments"]:
|
||||
message = comment_data.get("message", "")
|
||||
message = self._remove_think_blocks(message)
|
||||
message = self._escape_html_in_text(message) # ← Экранируем
|
||||
|
||||
comment = Comment(content=message, ...)
|
||||
```
|
||||
|
||||
### 2. Для общего summary
|
||||
|
||||
```python
|
||||
summary = await self.analyzer.generate_summary(...)
|
||||
summary = self._remove_think_blocks(summary)
|
||||
summary = self._escape_html_in_text(summary) # ← Экранируем
|
||||
|
||||
await git_service.create_review(body=summary, ...)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Тестирование
|
||||
|
||||
Создан тест для проверки:
|
||||
|
||||
```python
|
||||
test_texts = [
|
||||
"key должен быть на элементе <CharacterItem>, а не на <img>",
|
||||
"Используйте <div> вместо <span> здесь"
|
||||
]
|
||||
|
||||
for text in test_texts:
|
||||
escaped = escape_html_in_text(text)
|
||||
print(f"Original: {text}")
|
||||
print(f"Escaped: {escaped}")
|
||||
```
|
||||
|
||||
**Результат:**
|
||||
```
|
||||
Original: key должен быть на элементе <CharacterItem>, а не на <img>
|
||||
Escaped: key должен быть на элементе `<CharacterItem>`, а не на `<img>`
|
||||
|
||||
Original: Используйте <div> вместо <span> здесь
|
||||
Escaped: Используйте `<div>` вместо `<span>` здесь
|
||||
```
|
||||
|
||||
✅ **Работает как ожидалось!**
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Визуальное сравнение
|
||||
|
||||
### ❌ До исправления (в Gitea):
|
||||
|
||||
```
|
||||
❌ src/pages/search-character.tsx:105
|
||||
ERROR: Неправильное использование key: key должен быть на элементе , а не на
|
||||
↑ теги исчезли, непонятно о чем речь
|
||||
```
|
||||
|
||||
### ✅ После исправления (в Gitea):
|
||||
|
||||
```
|
||||
❌ src/pages/search-character.tsx:105
|
||||
ERROR: Неправильное использование key: key должен быть на элементе `<CharacterItem>`, а не на `<img>`
|
||||
↑ теги видны и кликабельны, все понятно
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Измененные файлы
|
||||
|
||||
- **`backend/app/agents/reviewer.py`**:
|
||||
- Добавлена функция `_escape_html_in_text()`
|
||||
- Вызов функции для комментариев
|
||||
- Вызов функции для summary
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Как попробовать
|
||||
|
||||
1. Backend уже подхватил изменения (`--reload`)
|
||||
2. Нажмите **🔄 Повторить ревью**
|
||||
3. Откройте PR в Gitea
|
||||
4. Проверьте что теги теперь видны: `<CharacterItem>`, `<img>`, и т.д.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Готово!
|
||||
|
||||
Теперь все HTML/JSX теги в комментариях **отображаются корректно** и код понятен! 🎉
|
||||
|
||||
**Попробуйте прямо сейчас!** 🧪
|
||||
|
||||
Reference in New Issue
Block a user