File size: 11,652 Bytes
900fbed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
03793f6
 
 
 
 
 
 
 
 
 
 
900fbed
 
 
 
 
 
 
 
 
 
 
1ac5fcd
 
 
 
 
 
 
 
 
 
 
 
 
207901a
1ac5fcd
 
207901a
 
299ec03
 
 
 
 
 
 
 
 
1ac5fcd
207901a
 
1ac5fcd
 
207901a
1ac5fcd
 
 
207901a
1ac5fcd
 
 
 
 
 
 
 
 
 
 
 
 
207901a
1ac5fcd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
Я разрабатываю 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