Spaces:
Paused
Paused
| Я разрабатываю AI-ассистента для учителей английского. Туда загружаешь фото страниц учебника, а также задаешь параметры. | |
| На выходе получаешь план урока. Фото считывается через vision. Везде используется API openai, эндпоинт responses (2025 год, | |
| это самый актуальный эндпоинт). Интерфейс реализуется на Gradio. Vision работает через загрузку в него временного url | |
| изображения страницы учебника. Блоки параметров: 1) Занятия - тема, основная цель, название учебника, уровень учебника | |
| (по CEFR, выпадающий список) 2) Методика (выпадающий список, там PPP, TTT и другие актуальные подходы и методики ESL - 5 разных). | |
| Занятие: кол-во учеников (ползунок от 2 до 40 и чекбокс "индивидуальное занятие", нажатие которого деактивирует ползунок), | |
| время занятия (ползунок от 20 до 120 минут), возраст (свободное поле с placeholder "напр. 10-11", и чекбокс "врослые", | |
| нажатие которого деактивирует свободное поле с возрастом), соответствие класса уровню - ползунок с 3 позициями mixed ability | |
| (предложи варианты, ведь бывает что учебник ниже уровня большинства, бывает наоборот ниже, бывает что в примерно в уровень, | |
| бывает полный mixed ability). Дальше - ччекбокс наличия домашнего задания, под ним - чекбокс доп. материалов из интернета. | |
| Обязательные поля должны быть заполнены для активации генерции, иначе при нажатии кнопки создания урока на месте плана урока | |
| возникает сообщение о необходимости заполнить обязательные поля. Оформлен интерфейс в 2 колонки - левая с настройками (1/3 ширины), | |
| правая с планом урока (2/3 ширины). Я тебе вышлю имеющуюся у меня заготовку - здесь корректна инициализация клиента, правильные | |
| названия эндпоинтов и моделей. Но здесь практически всё пока не то, что нужно - image_url сейчас подключается по условию, но оно | |
| должно всегда попадать в LLM для генерации и другое. Прежде чем начнем писать код, проговори всё, и задай если нужно вопросы. Код не пиши. | |
| На вопросы: 1. методики - давай пока оставим эти 2 - PPP и TTT. По умолчанию - PPP, так что поле необязательное (значение по умолчанию уже есть) 2.метки для уровня: | |
| “below”, “on-level”, “above”, “mixed” 3. Да, правильно 4. Если фото не загружено - урок не генерируется (это ключевая функция ассистента - создавать урок по загруженной странице) | |
| 5. Формат вывода - markdown внутри правого поля внутри Gradio - ок, но docx-экспорт через кнопку должен тоже быть (так же, как в приложении из примера) 6. | |
| 6. Заглушка web search - она не возвращает ничего, в prompt можно ее добавить при условии нажатия чекбокса как "используется web search | |
| 7. (пусть модель просто видит эту строчку если чекбокс нажат, а если отжат - там ничего) 7. Достаточно слайдера, о котором говорили выше. | |
| 8. Что еще забыли -- параметры тема и цель занятия. Тема необязательная, цель - тоже необязательная. Все настройки делим на блоки (аналогично тому | |
| 9. как в приложении примере есть блоки "ребенок" и "занятие"). В начале - блок "занятие" (учебник, уровень, тема, цель"), затем - класс (кол-во детей | |
| 10. (обязательное поле), возраст (обязательно), соответствие уровню учебника. Потом чекбоксы - наличие ДЗ и доп. материалы из интернета. Во всех полях | |
| 11. со свободным ответом должны быть плейсхолдеры с релевантным текстом-подсказкой | |
| Собираем все параметры в all_inputs (это список Gradio-компонентов). | |
| Передаём их в on_generate через inputs=all_inputs. | |
| Внутри on_generate используем locals(), чтобы автоматически получить словарь всех аргументов. | |
| Распаковываем их в generate_lesson_plan(**kwargs). | |
| мне нужно сделать простое приложение по генерации планов уроков на базе предоставленной фотографии страницы учебника. | |
| Для интерфейса используем streamlit. Логика такая - экран делится не левую и правую части. В левой части область загрузки | |
| фотографии страницы учебника + поля заполнения и настройки (они появляются после успешной загрузки). | |
| При загрузке файла и получения его url, url первый раз передается в LLM (gpt-4o-mini) через chat.completions. | |
| Промпт дает модели задание определить предмет (английский, математика и т.п.) и название учебника. | |
| Я предлагаю использовать structured output для этого. Предмет и название учебника попадают в поля, которые появляются под областью загрузки (в области слева). | |
| Если модель не смогла определить предмет и/или учебник - поля просто остаются пустыми и являются обязательнми для заполнения учителем. | |
| Это первый шаг. Второй шаг - это настройки. Учитель определяет количество детей в классе от 1 до 40 (ползунок) и нажимает кнопку "создать план урока", | |
| которая становится активна только после заполнения полей предмета и учебника. Ползунок количества детей изначально стоит на значении 10. | |
| Эти данные (предмет, учебник, количество детей в классе) передаются на второй запрос к chat.completions вместе с url страницы учебника. | |
| Этот второй запрос должен создать план урока по промпту. В промпте мы просим модель создать план урока на основании предоставленного изображения | |
| страницы учебника и на основании переданных данных (предмет, учебник, количество детей в классе) План урока должен обязательно опираться на | |
| предоставленный материал - где нужно указываются номера упражнений, примеры и так далее. | |
| Модель gpt-4o-mini поддержкивает input image. | |
| Длительное хранение загруженных изображений не требуется, поэтому решение tmpfiles.org подходит. | |
| Upload Image → (if auto_detect) → Vision API → Update Textbook Field → Show Form | |
| ↘ (else) → Show Form Immediately | |
| uploaded_image → upload_to_catbox() → public_url → передача в OpenAI | |
| Structured Outputs через response_format с JSON Schema , так как: | |
| from pydantic import BaseModel | |
| from openai import OpenAI | |
| class TextbookInfo(BaseModel): | |
| subject: str # Предмет (например, "Английский язык") | |
| textbook_name: str # Название учебника (например, "Spotlight 5") | |
| client = OpenAI() | |
| completion = client.beta.chat.completions.parse( | |
| model="gpt-4o-mini-2024-07-18", # Убедитесь, что модель поддерживает Structured Outputs | |
| messages=[ | |
| {"role": "system", "content": "Определи предмет и название учебника по изображению страницы. Если не уверен — оставь поля пустыми."}, | |
| {"role": "user", "content": [ | |
| {"type": "image_url", "image_url": {"url": uploaded_image_url}}, | |
| {"type": "text", "text": "Что это за учебник? Определи предмет и точное название."} | |
| ]} | |
| ], | |
| response_format=TextbookInfo # Автоматически генерирует JSON Schema | |
| ) | |
| textbook_data = completion.choices[0].message.parsed | |
| Image input: | |
| Analyze the content of an image | |
| response = client.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[{ | |
| "role": "user", | |
| "content": [ | |
| {"type": "text", "text": "What's in this image?"}, | |
| { | |
| "type": "image_url", | |
| "image_url": { | |
| "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg", | |
| }, | |
| }, | |
| ], | |
| }], | |
| ) | |
| print(response.choices[0].message.content) | |
| Вот так мы получаем url: | |
| def upload_image(image_bytes): | |
| """Загрузка изображения""" | |
| try: | |
| response = requests.post( | |
| "https://tmpfiles.org/api/v1/upload", | |
| files={"file": image_bytes}, | |
| timeout=10 | |
| ) | |
| return response.json()["url"].replace("tmpfiles.org/", "tmpfiles.org/dl/") | |
| except Exception as e: | |
| st.error(f"Ошибка загрузки: {e}") | |
| return None |