PanarinI commited on
Commit
03793f6
·
1 Parent(s): 28d6562
README.md CHANGED
@@ -5,7 +5,7 @@ colorFrom: gray
5
  colorTo: pink
6
  sdk: gradio
7
  sdk_version: 5.25.2
8
- app_file: app/test_gradio.py
9
  pinned: false
10
  ---
11
 
 
5
  colorTo: pink
6
  sdk: gradio
7
  sdk_version: 5.25.2
8
+ app_file: app/test_gradio_test.py
9
  pinned: false
10
  ---
11
 
TASKS.md CHANGED
@@ -19,8 +19,8 @@
19
  [ ] интеграция настроек
20
  [ ] мотивационный блок в приложении - напр. цитата из педагогики, мотивационная, каждый раз новая
21
 
22
- [ ]
23
-
24
  ## in progress
25
 
26
  [ ] проверка различных основных учебников
 
19
  [ ] интеграция настроек
20
  [ ] мотивационный блок в приложении - напр. цитата из педагогики, мотивационная, каждый раз новая
21
 
22
+ [ ] можно превратить в интерактивный обучающий курс. Где части плана объясняются, поясняется методика, даются ссылки на видео с уроками и тд. Вдохновение: https://maxenglishcorner.com/lessons/teaching-ideas/teaching-ideas-7-lesson-planning-ppp-model/
23
+ [ ] эту идею описать в портфолио как продолжение MVP
24
  ## in progress
25
 
26
  [ ] проверка различных основных учебников
app/__init__.py ADDED
File without changes
app/instructions.py CHANGED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ def get_instructions(
3
+ methodology: str,
4
+ cefr: str,
5
+ topic: str,
6
+ goal: str,
7
+ age: str,
8
+ adults: bool,
9
+ level_match: int,
10
+ duration: int,
11
+ inventory: str,
12
+ hw_required: bool,
13
+ web_search: bool,
14
+ repetition: bool,
15
+ application: bool,
16
+ analysis: bool,
17
+ creativity: bool
18
+ ) -> str:
19
+ """Генерирует промпт для OpenAI на основе параметров урока."""
20
+
21
+ # Пример форматирования (можно менять как угодно)
22
+ prompt = f"""
23
+ Ты — преподаватель английского, работающий по методике **{methodology}**.
24
+
25
+ **Параметры урока:**
26
+ **Учебник**: {textbook}",
27
+ **CEFR-уровень**: {'определи по загруженной странице' if cefr.strip() == '' else cefr}",
28
+ **Тема**: {topic or 'определи по загруженной странице'}",
29
+ **Цель занятия**: {goal or 'определи по загруженной странице'}",
30
+ **Формат**: {format_type} ({num_students} {'ребёнок' if num_students == 1 else 'детей'})",
31
+ **Возраст**: {'взрослые' if adults else age}",
32
+ **Соответствие уровня**: {['below', 'on-level', 'above', 'mixed'][level_match]}",
33
+ **Длительность**: {duration} минут",
34
+ **Инвентарь**: {inventory if inventory else 'стандартный'}",
35
+ **Методика**: {methodology}",
36
+ **Дополнительная информация**: {extra_info}"
37
+
38
+ **Домашнее задание**: {'да' if hw_required else 'нет'}"
39
+
40
+ Сгенерируй план урока, учитывая эти параметры.
41
+ """
42
+ return prompt
43
+
44
+
45
+ INSTRUCTIONS_1=f"""
46
+ Ты — AI-ассистент для учителей английского, экспертно владеющий методологией {methodology}].
47
+ Сначала спланируй логику урока по этапам, затем сгенерировать конспект».
48
+
49
+ Используй методику PPP (Presentation-Practice-Production) для построения урока для школьников. Урок должен состоять из трех этапов:
50
+ 1. **Презентация**: Представь новую тему, объясни грамматические или лексические аспекты с примерами.
51
+ 2. **Практика**: Подготовь упражнения для закрепления знаний, например, заполнение пропусков, тесты с вариантами ответа.
52
+ 3. **Продукция**: Предложи задания, в которых ученики могут применить новые знания в реальных ситуациях, например, ролевые игры или диалоги.
53
+
54
+ Учитывай:
55
+ - Уровень учащихся (например, A1, B1, C1) и соответствующие задания.
56
+ - Возрастную категорию учащихся (от 10 до 18 лет).
57
+ - Формат занятия: индивидуальное или групповое.
58
+ - Длительность урока (например, 60 минут) и соответствующее количество заданий.
59
+ - Домашнее задание (если требуется).
60
+ - Дополнительные материалы (если нужно, используй интернет-ресурсы).
61
+
62
+ """
app/knowledge_base/LP_shots.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ LP_PPP_1 = f"""
2
+ CLASS - - - Intermediate level, 4 students
3
+ THEME FOR CLASS - - - Pollution
4
+ TARGET LANGUAGE (TL) - - - 1st and 2nd conditonals
5
+ OBJECTIVE FOR CLASS - - - By the end of the class the students should be able to know the difference between
6
+ first and second conditionals and be able to use both forms while speaking about pollution.
7
+ MATERIALS - - -
8
+ ● 3 pictures to be used in the CONTEXT stage (from Pixabay)
9
+ ●Handout 1 - Reading: Article about air pollution plus corresponding reading exercises
10
+ citation: (This article was written by Katy Daigle and has been adapted from
11
+ https://www.sciencenewsforstudents.org/article/air-pollution-shortening-lives-worldwide)
12
+ ●Handout 2 - Worksheet for PRACTICE activities with summary reference chart at top of page
13
+
14
+ ---
15
+ 1. CONTEXT or WARMER/THEME
16
+
17
+ OBJECTIVE(S)
18
+ ●To get the students speaking and communicating a little in English.
19
+ ●To orientate students to begin thinking of different kinds of pollution. There are three
20
+ pictures (one each of air, land and water pollution).
21
+
22
+ MATERIALS
23
+ 3 pictures from Pixabay
24
+ (different kinds of pollution: air, land & water)
25
+ Students are placed into pairs (more intimate groups this way, and more students will be speaking) and given 3
26
+ pictures. Together they have to
27
+ 1) Describe each picture individually
28
+ 2) Decide what all three pictures have in common
29
+ Teacher monitors and helps out a little if there are problems with vocabulary
30
+ After the pair-work the teacher asks the students to say what they came up with
31
+
32
+
33
+ 2. INTRODUCTION
34
+
35
+ OBJECTIVE(S)
36
+ ● To pre-teach some vocabulary found in the reading (ex: lifespan)
37
+ ●To orientate students to some of the content (concepts) in the article
38
+
39
+ MATERIALS
40
+ none, other than the whiteboard
41
+
42
+
43
+ ●Elicit the meaning of ‘lifespan’ from the class
44
+ ●Ask the students to answer the question written on the board:
45
+ What are some common causes for shorter life spans in some countries? (for example diet, pollution and cancer)
46
+
47
+
48
+ 3. INPUT TASK 1: READING FOR GIST
49
+
50
+ OBJECTIVE(S)
51
+ ● To have the students get a general idea of what the text is about
52
+ without getting bogged down with unfamiliar vocabulary or some unclear parts or ideas
53
+ MATERIALS Handout 1 with article and two sets of questions. One set is for
54
+ this task where the students have to decide which of the three given titles is most suitable
55
+ ●The students are given a handout which contains both the article to read and two sets of questions. The students are
56
+ asked to fold their papers so they could focus completely on that first task (and not reading ahead to see what is next on
57
+ the handout).
58
+ ●Students understand the task before they begin reading and are given only one minute to decide which title would be
59
+ best for the article.
60
+ ●After one minute students are asked not only for their answer, but also why the other options were not correct or
61
+ suitable.
62
+
63
+
64
+ 4. INPUT TASK 2: READING FOR DETAILS
65
+
66
+ OBJECTIVE(S) ●
67
+ To have the students get a better idea of what the text is about
68
+ by quickly scanning it for specific information
69
+ MATERIALS Handout 1 with article and two sets of questions. This task is the
70
+ second set of 3 questions found at the bottom of the article
71
+
72
+ ● Students are told to look at Section 2 on their handout
73
+ ●We go over the questions so the students understand what they have to read for
74
+ ●Students work out the answers individually but can check with other students
75
+ ●The answers are elicited and explained.
76
+
77
+ 5. PRESENTATION
78
+
79
+ OBJECTIVE(S)
80
+ ● To familiarize the students with how the first and second
81
+ conditionals are formed and to know what situations are appropriate to use which one
82
+ MATERIALS
83
+ The form, concepts and examples are written on the board
84
+
85
+ ●Ask the students what they know about the grammatical structure of conditionals.
86
+ ●Focus on what they know about the first and second conditionals and write the information on the board in a clear and
87
+ organized way (which resembles the chart in Handout 2.
88
+ ●Review the key points by asking different students comprehension check questions to see what they understand and
89
+ how well they are retaining the key information.
90
+
91
+ 6. PRACTICE 1 CORRECT SENTENCES
92
+
93
+ OBJECTIVE(S) ● To test for level of understanding as students apply some of the
94
+ recently reviewed key concepts by correcting 4 sentences with errors emphasizing those
95
+ points.
96
+ MATERIALS Handout 2 with a chart for reference of key idea (#1) and the task
97
+ of correcting the four sentences (#2)
98
+
99
+ ●Point out the 4 sentences in Section 2 and tell the students to correct them.
100
+ ●Monitor the students while they are working to see what they find difficult.
101
+ ●Elicit the answers and their explanations / Also deal with their doubts as we go over their answers.
102
+ ●Review the key points before going on to Practice 2
103
+
104
+ 7a. PRACTICE 2a WRITE & USE QUESTIONS 1-ST CONDITIONAL
105
+
106
+ OBJECTIVE(S)
107
+ ● To have the students come up with their own sentences using the
108
+ first conditional structure for an appropriate situation, matching the form with the function
109
+ ● To have the students become familiar with incorporating the TL into their speaking
110
+ MATERIALS
111
+ Handout 2 Section #3
112
+ ●Focus on only the first conditional as the TL (target language) and elicit the key points to orientate the students.
113
+ ●Students look at Section #3 on Handout 2 and teacher elicits different possible questions they could ask in that form.
114
+ ●Students individually write first conditional questions to ask a partner in the class. Teacher monitors and helps.
115
+ ●Model the coming speaking application by having one student ask another his/her question and the partner replies.
116
+ Encourage them to explore a little further by changing it into a ‘mini one-minute conversation’ through asking followup questions and volunteering comments or details.
117
+ ●Place students in pairs and have them take turns with their questions which lead them to their mini conversations.
118
+ ●Give some feedback when they are finished, looking both at the target language used and their development of the
119
+ mini conversations.
120
+
121
+ 7b. PRACTICE 2b WRITE & USE QUESTIONS 2ND CONDITIONAL
122
+
123
+ OBJECTIVE(S)
124
+ ● To have the students come up with their own sentences using the
125
+ second conditional structure for an appropriate situation, matching the form with the
126
+ function
127
+ ● To have the students become familiar with incorporating the TL into their speaking
128
+ MATERIALS Handout 2 Section #4
129
+ ●Focus on only the second conditional and elicit the key points to orientate the students.
130
+ ●Basically the same procedure as the previous exercise, but now for Section 4 and focusing on the second conditional.
131
+
132
+ 7c. PRACTICE 3 PREPARE FOR DISCUSSION
133
+
134
+ OBJECTIVE(S)
135
+ ● To help students prepare for coming discussion
136
+ MATERIALS Handout 2 Section #5
137
+ Some prompts in Section #6 they can use in their conversation
138
+ ●Tell the students that soon they will have a discussion about the theme of air pollution. They are to talk about how
139
+ bad it is and what can be done about it. Elicit some possible sentences/questions for the two conditionals as examples.
140
+ ●Students each write one first conditional sentence or question and another one in the second conditional that they
141
+ might use in that discussion.
142
+ ●Teacher monitors and helps.
143
+ ●Because there are only four students, place them all in the same group and tell them they are enjoying a cup of coffee
144
+ together. They are to imagine that the conversation has turned to air pollution and without referring to their notes, they
145
+ talk about how bad the situation is and speculate what could be done about it, using occasionally, if it’s appropriate, the
146
+ first or second conditional. The main focus is to have a conversation and that they should explore the theme.
147
+ ●Go over the expressions in Section #6 that they can use while speaking and write them on the board as prompts
148
+ ●Teacher listens and steps in, if necessary, to guide and encourage the students to explore the theme in their
149
+ conversation.
150
+ ●Give some feedback when they are finished, looking both at the target language used and their development of the
151
+ discussion.
152
+
153
+
154
+ 8. PRODUCTION
155
+
156
+ OBJECTIVE(S)
157
+ ● To use the two conditionals in a Production speaking activity
158
+ MATERIALS
159
+ none
160
+
161
+ ●Tell the students they are going to have one more conversation using the first and second conditional. This time it
162
+ will be about land and water pollution or pollution in general.
163
+ ●Tell them they can think for a couple of minutes about what they may say or ask about that theme. Remind them of
164
+ some of the things that came up in the previous speaking activity. Also tell them that the teacher will not be
165
+ participating; that it will be just their conversation.
166
+ ●Students speak for about 5 minutes.
167
+ ●Give some feedback when they are finished, looking both at the target language used and their development of the
168
+ discussion.
169
+ """
170
+
171
+ LP_PPP_2 = f"""
172
+ 1 OBJECTIVES
173
+ By the end of the class the students should be able to use the past continuous while engaging in a conversation about what they did last weekend
174
+
175
+ 2 CONTEXT
176
+ ●Show some pictures of people doing fun or relaxing things and students describe them (learning the relevant vocabulary such as the action verbs – reading a book, playing tennis, etc)
177
+ ●Then the students ask the teacher questions to find out what s/he did last weekend or typically does on the weekend. (It’s fine if the students don’t use the past continuous and they shouldn’t be expected to if they haven’t been taught it yet. In fact, the past continuous isn’t part of the lesson plan until later in the Presentation stage).
178
+
179
+ 3 INPUT TASK 1: READING FOR GIST
180
+ Best title
181
+ ●Write on the board 3 titles and tell the students they have to decide which one (A, B or C) is the most suitable for the reading.
182
+ ●Give the students the reading and 60 seconds to complete the task.
183
+ ●Ask the students to say their choice(s) and say why. When all the choices have been gone over, tell them the correct answer.
184
+
185
+ 4 INPUT TASK 2: READING FOR SPECIFIC INFORMATION
186
+ ●Give the students a handout with six sentences. All six sentences reflect what happened in the text they just read, but each sentence has one mistake. Students are asked to look at the example of the first sentence and make similar corrections for the remaining five. NOTE: These mistakes reflect understanding the contents of the text, NOT any grammar errors. Ex: Julie went to the market on Saturday. Friday
187
+ ●Students complete task individually, compare answers with another student, then go over their answers as a class.
188
+ © maxenglishcorner.com 2020 PPP lesson planning example 2
189
+
190
+ 5 PRESENTATION 1
191
+ PAST CONTINUOUS: Form & Ongoing Action in Past
192
+ ●Write on the board two sentences found in the first paragraph of the text. Ex: There was a lot of traffic. Lots of people were going to the beach.
193
+ ●Elicit the names of the two verb forms and write them above the examples.
194
+ ●Elicit the structure of each. (regular verb in past simple form = verb + ED) (past continuous verb has 2 parts: be auxiliary in past + verb in ING form) ●Elicit how to create the negative forms and write those sentences on the board ●Elicit how to create a WH question (and answer) ●Elicit how to create a YES/NO question (and positive & negative answer) ●Elicit when to use the past continuous. (Focus on Concepts 1 & 2 but accept others) These concepts are explained in Part D of The PPP Model Explained and refer to particular situations that would be appropriate for using the past continuous. You want the students to understand that they can use the past continuous form when describing a general situation happening in the past (ex: It was raining yesterday), or when a particular action lasted for a period of time and you want to bring attention to that (ex: It was raining all night).
195
+ ●Before continuing on to the Practice tasks, ask different students comprehension check questions, testing them on what they understand of what has been presented so far.
196
+ 6 PRACTICE set 1
197
+ PRACTICE 1-1
198
+ ●Give students worksheet. Explain exercise 1-1: There are 5 gap-fill sentences to complete, writing the past continuous form with the provided prompts. Ex: She __________ football yesterday. (not play) (She wasn’t playing football yesterday.)
199
+ ●Students do it individually, check in pairs, then go over answers with class
200
+ PRACTICE 1-2
201
+ ●Exercise 2 on worksheet. Students invent answers to respond to WH and Yes/No questions. Ex: What were they doing? __________ (They were sleeping. – for example) Was he studying? (+) __________ OR (-) __________ (Yes, he was. OR No, he wasn’t.) ●Model one or two examples first.
202
+ ●As above, students do it individually, check in pairs, then the answers are gone over
203
+ PRACTICE 1-3
204
+ Have the students ask you past continuous questions about your last weekend. Encourage both WH & Yes/No questions. Allow other questions too, like past simple and present simple, and if they make mistakes, guide them by eliciting the right form of question to ask or the key elements which would help them decide which form to use.
205
+ 7 PRESENTATION 2
206
+ PAST CONTINUOUS: Action happening at a specific time in the past
207
+ ●Write on the board the following question and answer: What were you doing at ten o’clock last night? I was watching TV.
208
+ ●Elicit if the action was for a duration (ex: for 3 hours) (No), a description in general (ex: the sun was shining) (No) or for an action happening (in progress) at a specific time in the past (Yes!)
209
+ © maxenglishcorner.com 2020 PPP lesson planning example 2
210
+ ●Point out that this is a different function (situation to use the verb tense). Ask students if there are any changes to the form in the question or answer. (No)
211
+ ●Draw a time line (see Concept #5) As in Presentation 1, the past continuous can be used in different situations. In this case it is for a continuous action happening at a certain point in time in the past.
212
+ ●Elicit or provide more WH questions: - - What were you watching on TV (at that time)? - - Who were you watching TV with (at that time)? - - What were you doing at 11:00 last night?
213
+ ●And elicit some Yes/No questions:
214
+ - - Were you watching TV at 10:30? (Yes, I was. // No, I wasn’t.) - - Were you eating at 6:15?
215
+ 8 PRACTICE set 2
216
+ PRACTICE 2-1
217
+ ●Students write questions to ask partner about last night (with specific times). If students seem to be able to handle it, ask them to write two WH questions and two Yes/No questions. If not, do 3 WH questions only. ●Teacher monitors and helps/guides when necessary.
218
+ PRACTICE 2-2
219
+ ●Students are placed into pairs. One student is to ask a WH question, and the other answers it. Model first with two students so they are clear on the task instructions. Then students carry out the task and the teacher monitors. ●In the same pairs, students change roles.
220
+ PRACTICE 2-3
221
+ ●If only WH questions were done previously, then repeat tasks 2-1 and 2-2 but for Yes/No questions this time.
222
+ 9 PRESENTATION 3
223
+ Focus on enriching the students’ approach to speaking
224
+ ●Teacher goes into ‘hot seat’ role where students have to ask WH and Yes/No questions about what s/he was doing yesterday. ●Teacher points out that simply asking a list of unrelated questions soon exhausts the activity. The students can enrich their speaking by 1) asking follow-up questions – not all of which have to be in the past continuous form (ex: Do you do that every night?) 2) making comments – (ex: That’s interesting. Me too. I was doing that too.) 3) volunteering information about themselves – I don’t like to watch TV. I prefer to do other things in my free time…..) ●Teacher chooses one student to be in the hot seat and the class asks that person about her/his day yesterday. The teacher encourages follow-up questions, comments from the class, as well as volunteering information about themselves.
225
+ © maxenglishcorner.com 2020 PPP lesson planning example 2 10 PRACTICE set 3
226
+ PRACTICE 3-1
227
+ ●Students are divided into groups of 3 or 4, one person in each group is in the hot seat, and they ask and speak about yesterday. (Some questions and sentences are in the past continuous, but many aren’t.) Teacher monitors. ●After a few minutes the teacher tells the students to select a new person for the hot seat. Teacher monitors.
228
+ After a few more minutes teacher stops activity and addresses class, offering a little feedback (such as encouragement, advice and eliciting corrections to some mistakes).
229
+ PRACTICE 3-2 Dress Rehearsal for Production Speaking Activity
230
+ ●Students stay in the same groups. Rather than focusing on just one person who is in a hot seat role, tell them to imagine they are having a coffee together and a short conversation about what they did yesterday. Encourage the people to all participate, volunteer information, make comments and ask questions, including follow-up questions.
231
+ ●Teacher monitors and prompts them as the students attempt to have a conversation for five minutes.
232
+ ●At the end of the activity, teacher gives some feedback such as tips, recognition of what they were doing well, some corrections on mistakes made when using the past simple or continuous, and more encouragement for everyone to participate in the conversation.
233
+ 11 PRODUCTION
234
+ ●The teacher changes the groups so there are new members in each group.
235
+ ●The students are told to do the same thing as before, only now the theme of their conversation is to talk about last weekend. They can find out how their weekends were similar or different, and if the weekend was unusual or like every other weekend.
236
+ ●This time the teacher does not intervene and s/he tells them so. They will have up to 5 minutes to speak about the theme and the teacher will not be participating or helping in any way. It is up to them to maintain the conversation.
237
+ ●The students engage in their conversations the best they can.
238
+ 12 FEEDBACK
239
+ ●As with the dress rehearsal, the teacher gives feedback in the form of corrections, tips and reminders, and pointing out what the students did well.
240
+ HOMEWORK
241
+ ●The students have to write 150 words about what they did last weekend, including at least one example of the past continuous for Concept 1* and at least one example of Concept 5*.
242
+ *NOTE: ‘Concept 1’ and ‘Concept 5’ are not the official names or numbers of these referenced situations. They were only used for the purposes of this article and can be seen as they were presented in The PPP Model Explained, Section D. They could very easily be called Situation 1 and Situation 2 or any other title that the teacher may prefer to use.
243
+ """
app/knowledge_base/Methods.md ADDED
@@ -0,0 +1 @@
 
 
1
+ Метод PPP даёт прочный каркас, а гибкость в упражнениях позволяет адаптировать урок под возраст и уровень учеников.
app/knowledge_base/inspire.md ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ The theories behind it, the materials and activities that become part of it, the suggestions and the models one can follow, all have to deal with the inevitable:
2
+ that it is only a plan and whatever shape it takes, it is to be used in the classroom.
app/knowledge_base/lesson_frameworks.md ADDED
@@ -0,0 +1 @@
 
 
1
+ ва ва
app/main.py CHANGED
@@ -1,245 +0,0 @@
1
- import streamlit as st
2
- from openai import OpenAI, BadRequestError
3
- from pydantic import BaseModel
4
- import requests
5
- import logging
6
- import os
7
- from dotenv import load_dotenv
8
-
9
- # 1. Конфигурация полей формы
10
- FORM_CONFIG = {
11
- "main_fields": {
12
- "subject": {"label": "Предмет", "type": "text", "default": ""},
13
- "textbook": {"label": "Название учебника", "type": "text", "default": ""},
14
- "students": {"label": "Количество учеников", "type": "slider", "min": 1, "max": 40, "default": 10},
15
- "methodology": {
16
- "label": "Методика обучения",
17
- "type": "selectbox",
18
- "options": ["PPP", "TTT"],
19
- "default": "PPP"
20
- }
21
- }
22
- }
23
-
24
- AUTO_DETECT_ENABLED = True # Флаг по умолчанию
25
-
26
- # 2. Первая команда Streamlit (должна быть первой)
27
- st.set_page_config(page_title="Генератор планов уроков", layout="wide")
28
-
29
- # 3. CSS для отключения running состояний
30
- st.markdown("""
31
- <style>
32
- [data-testid="stStatusWidget"] {
33
- display: none !important;
34
- }
35
- .stTextInput, .stSlider, .stSelectbox {
36
- opacity: 1 !important;
37
- }
38
- </style>
39
- """, unsafe_allow_html=True)
40
-
41
- # 4. Настройка логирования
42
- logging.basicConfig(
43
- level=logging.INFO,
44
- format='%(asctime)s - %(levelname)s - %(message)s',
45
- handlers=[logging.StreamHandler()]
46
- )
47
- logger = logging.getLogger(__name__)
48
-
49
- # 5. Загрузка переменных окружения
50
- load_dotenv()
51
- API_KEY = os.getenv("API_KEY_openai")
52
-
53
-
54
- if not API_KEY:
55
- logger.error("API_KEY_openai не найден в переменных окружения")
56
- st.error("Ошибка: API_KEY_openai не найден. Проверьте файл .env")
57
- st.stop()
58
-
59
- # 6. Инициализация клиента OpenAI
60
- client = OpenAI(api_key=API_KEY)
61
-
62
-
63
- # 7. Модель данных
64
- class TextbookInfo(BaseModel):
65
- subject: str = ""
66
- textbook_name: str = ""
67
-
68
-
69
- # 8. Функция загрузки изображения
70
- def upload_to_catbox(file_bytes):
71
- try:
72
- with st.spinner("Загрузка изображения на сервер..."):
73
- response = requests.post(
74
- "https://catbox.moe/user/api.php",
75
- files={"fileToUpload": file_bytes},
76
- data={"reqtype": "fileupload"}
77
- )
78
- response.raise_for_status()
79
- url = response.text.strip()
80
- if not url.startswith("https://files.catbox.moe/"):
81
- raise ValueError("Некорректный URL")
82
- return url
83
- except Exception as e:
84
- logger.error(f"Ошибка загрузки: {e}")
85
- st.error("Не удалось загрузить изображение")
86
- return None
87
-
88
-
89
- # 9. Функция парсинга ответа
90
- def parse_response(text: str) -> tuple[str, str]:
91
- subject = "Не определено"
92
- textbook = "Не определено"
93
-
94
- lines = text.lower().replace("*", "").strip().split('\n')
95
- for line in lines:
96
- if "предмет:" in line:
97
- subject = line.split("предмет:")[1].strip().capitalize()
98
- elif "учебник:" in line:
99
- textbook = line.split("учебник:")[1].strip().capitalize()
100
-
101
- return subject, textbook
102
-
103
-
104
- # 10. Инициализация состояний
105
- if "textbook_data" not in st.session_state:
106
- st.session_state.textbook_data = TextbookInfo()
107
- if "image_url" not in st.session_state:
108
- st.session_state.image_url = None
109
- if "form_values" not in st.session_state:
110
- st.session_state.form_values = {
111
- field: config["default"]
112
- for field, config in FORM_CONFIG["main_fields"].items()
113
- }
114
- if "force_form_update" not in st.session_state:
115
- st.session_state.force_form_update = True
116
-
117
- # 11. Основной интерфейс
118
- left_col, right_col = st.columns([2, 3])
119
-
120
- with left_col:
121
- st.header("Настройки")
122
- AUTO_DETECT_ENABLED = st.toggle(
123
- "Автоматическое распознавание учебника",
124
- value=True,
125
- key="auto_detect_toggle"
126
- )
127
- st.header("Загрузка учебника")
128
- uploaded_file = st.file_uploader("Выберите изображение страницы", type=["jpg", "png", "jpeg"])
129
-
130
- # Обработка загрузки изображения
131
- if uploaded_file and not st.session_state.image_url:
132
- image_url = upload_to_catbox(uploaded_file.getvalue())
133
- if image_url:
134
- st.session_state.image_url = image_url
135
- st.success("Изображение загружено!")
136
-
137
- if AUTO_DETECT_ENABLED: # Только если включено
138
- with st.spinner("Анализ изображения..."):
139
- try:
140
- response = client.chat.completions.create(
141
- model="gpt-4o-mini",
142
- messages=[
143
- {
144
- "role": "user",
145
- "content": [
146
- {"type": "image_url", "image_url": {"url": image_url}},
147
- {"type": "text", "text": """Определи предмет и учебник. Ответь строго в формате:
148
- Предмет: [название]
149
- Учебник: [название]"""}
150
- ]
151
- }
152
- ]
153
- )
154
-
155
- if response.choices:
156
- subject, textbook = parse_response(response.choices[0].message.content)
157
- st.session_state.textbook_data = TextbookInfo(
158
- subject=subject,
159
- textbook_name=textbook
160
- )
161
- st.session_state.force_form_update = True
162
-
163
- except Exception as e:
164
- logger.error(f"Ошибка анализа: {e}")
165
- st.error("Ошибка при анализе изображения")
166
- else:
167
- st.info("Автораспознавание отключено. Заполните данные вручную")
168
- st.session_state.textbook_data = TextbookInfo()
169
- st.session_state.force_form_update = True
170
-
171
- # Форма с настройками
172
- if st.session_state.image_url:
173
- st.subheader("Данные учебника")
174
-
175
- # Обновление значений формы при необходимости
176
- if st.session_state.force_form_update:
177
- st.session_state.form_values.update({
178
- "subject": st.session_state.textbook_data.subject,
179
- "textbook": st.session_state.textbook_data.textbook_name
180
- })
181
- st.session_state.force_form_update = False
182
-
183
- with st.form(key="lesson_form"):
184
- # Динамическое создание полей из конфига
185
- for field, config in FORM_CONFIG["main_fields"].items():
186
- if config["type"] == "text":
187
- st.session_state.form_values[field] = st.text_input(
188
- config["label"],
189
- value=st.session_state.form_values[field],
190
- key=f"form_{field}"
191
- )
192
- elif config["type"] == "slider":
193
- st.session_state.form_values[field] = st.slider(
194
- config["label"],
195
- min_value=config["min"],
196
- max_value=config["max"],
197
- value=st.session_state.form_values[field],
198
- key=f"form_{field}"
199
- )
200
- elif config["type"] == "selectbox":
201
- st.session_state.form_values[field] = st.selectbox(
202
- config["label"],
203
- options=config["options"],
204
- index=config["options"].index(st.session_state.form_values[field]),
205
- key=f"form_{field}"
206
- )
207
-
208
- submitted = st.form_submit_button("Создать план урока")
209
-
210
- if submitted:
211
- if not st.session_state.form_values["subject"] or not st.session_state.form_values["textbook"]:
212
- st.warning("Заполните все обязательные поля")
213
- else:
214
- with st.spinner("Генерация плана урока..."):
215
- try:
216
- response = client.chat.completions.create(
217
- model="gpt-4o-mini",
218
- messages=[
219
- {
220
- "role": "system",
221
- "content": "Ты опытный учитель. Создай детальный план урока."
222
- },
223
- {
224
- "role": "user",
225
- "content": [
226
- {"type": "image_url", "image_url": {"url": st.session_state.image_url}},
227
- {"type": "text", "text": f"""
228
- Создай план урока по методике {st.session_state.form_values['methodology']}
229
- Детали:
230
- - Предмет: {st.session_state.form_values['subject']}
231
- - Учебник: {st.session_state.form_values['textbook']}
232
- - Учеников: {st.session_state.form_values['students']}
233
- """}
234
- ]
235
- }
236
- ]
237
- )
238
- right_col.markdown(response.choices[0].message.content)
239
- except Exception as e:
240
- st.error(f"Ошибка генерации: {e}")
241
-
242
- with right_col:
243
- st.header("План урока")
244
- if not st.session_state.image_url:
245
- st.info("Загрузите изображение учебника")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/prompt_builder/__init__.py ADDED
File without changes
app/prompt_builder/methodology.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ METHODOLOGY_DATA = {
2
+ "PPP": {
3
+ "structure": "3 этапа: Presentation → Practice → Production",
4
+ "key_points": [
5
+ "Четкое разделение этапов",
6
+ "Контролируемая практика перед свободным использованием",
7
+ "Пример: Демонстрация диалога → Упражнения на подстановку → Ролевая игра"
8
+ ]
9
+ },
10
+ "TTT": {
11
+ "structure": "Test → Teach → Test",
12
+ "key_points": [
13
+ "Диагностика текущего уровня перед обучением",
14
+ "Фокус на пробелах в знаниях",
15
+ "Пример: Предварительный квиз → Объяснение проблемных мест → Финальное задание"
16
+ ]
17
+ }
18
+ }
app/prompt_builder/prompt.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ METHODOLOGY_TIPS = {
2
+ "PPP": """
3
+ [МЕТОДИКА PPP]
4
+ Обязательные этапы:
5
+ 1. Presentation (5-10 мин): Покажи пример через диалог/текст
6
+ 2. Practice (15 мин): Упражнения на подстановку/трансформацию
7
+ 3. Production (20 мин): Ролевая игра или создание своего контента
8
+ Пример: стр. 45 учебника → упражнение 3A → написание диалога
9
+ """,
10
+
11
+ "TTT": """
12
+ [МЕТОДИКА TTT]
13
+ Обязательные этапы:
14
+ 1. Test (10 мин): Диагностический тест
15
+ 2. Teach (15 мин): Объяснение проблемных мест
16
+ 3. Test (20 мин): Применение в новой ситуации
17
+ Пример: предтест на времена → объяснение Past Perfect → кейсы
18
+ """
19
+ }
20
+
21
+
22
+ def build_prompt(params):
23
+ base_prompt = f"""
24
+ СОЗДАЙ ПЛАН УРОКА по этим данным:
25
+ - Учебник: {params['textbook']}
26
+ - Страница: {params['image_url']} (все задания с этой страницы!)
27
+ - Уровень: {params['cefr']}
28
+ - Тема: {params['topic']}
29
+ - Цель: {params['goal']}
30
+ - Время: {params['duration']} мин
31
+ - Ученики: {params['num_students']} чел, возраст: {params['age']}
32
+
33
+ Особые указания:
34
+ """
35
+
36
+ # Добавляем советы по методике
37
+ methodology_advice = METHODOLOGY_TIPS.get(params['methodology'], "")
38
+
39
+ return base_prompt + methodology_advice
app/test.py CHANGED
@@ -1,245 +0,0 @@
1
- import streamlit as st
2
- from openai import OpenAI, BadRequestError
3
- from pydantic import BaseModel
4
- import requests
5
- import logging
6
- import os
7
- from dotenv import load_dotenv
8
-
9
- # 1. Конфигурация полей формы
10
- FORM_CONFIG = {
11
- "main_fields": {
12
- "subject": {"label": "Предмет", "type": "text", "default": ""},
13
- "textbook": {"label": "Название учебника", "type": "text", "default": ""},
14
- "students": {"label": "Количество учеников", "type": "slider", "min": 1, "max": 40, "default": 10},
15
- "methodology": {
16
- "label": "Методика обучения",
17
- "type": "selectbox",
18
- "options": ["PPP", "TTT"],
19
- "default": "PPP"
20
- }
21
- }
22
- }
23
-
24
- AUTO_DETECT_ENABLED = True # Флаг по умолчанию
25
-
26
- # 2. Первая команда Streamlit (должна быть первой)
27
- st.set_page_config(page_title="Генератор планов уроков", layout="wide")
28
-
29
- # 3. CSS для отключения running состояний
30
- st.markdown("""
31
- <style>
32
- [data-testid="stStatusWidget"] {
33
- display: none !important;
34
- }
35
- .stTextInput, .stSlider, .stSelectbox {
36
- opacity: 1 !important;
37
- }
38
- </style>
39
- """, unsafe_allow_html=True)
40
-
41
- # 4. Настройка логирования
42
- logging.basicConfig(
43
- level=logging.INFO,
44
- format='%(asctime)s - %(levelname)s - %(message)s',
45
- handlers=[logging.StreamHandler()]
46
- )
47
- logger = logging.getLogger(__name__)
48
-
49
- # 5. Загрузка переменных окружения
50
- load_dotenv()
51
- API_KEY = os.getenv("API_KEY")
52
- BASE_URL = os.getenv("BASE_URL")
53
-
54
- if not API_KEY:
55
- logger.error("API_KEY не найден в переменных окружения")
56
- st.error("Ошибка: API_KEY не найден. Проверьте файл .env")
57
- st.stop()
58
-
59
- # 6. Инициализация клиента OpenAI
60
- client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
61
-
62
-
63
- # 7. Модель данных
64
- class TextbookInfo(BaseModel):
65
- subject: str = ""
66
- textbook_name: str = ""
67
-
68
-
69
- # 8. Функция загрузки изображения
70
- def upload_to_catbox(file_bytes):
71
- try:
72
- with st.spinner("Загрузка изображения на сервер..."):
73
- response = requests.post(
74
- "https://catbox.moe/user/api.php",
75
- files={"fileToUpload": file_bytes},
76
- data={"reqtype": "fileupload"}
77
- )
78
- response.raise_for_status()
79
- url = response.text.strip()
80
- if not url.startswith("https://files.catbox.moe/"):
81
- raise ValueError("Некорректный URL")
82
- return url
83
- except Exception as e:
84
- logger.error(f"Ошибка загрузки: {e}")
85
- st.error("Не удалось загрузить изображение")
86
- return None
87
-
88
-
89
- # 9. Функция парсинга ответа
90
- def parse_response(text: str) -> tuple[str, str]:
91
- subject = "Не определено"
92
- textbook = "Не определено"
93
-
94
- lines = text.lower().replace("*", "").strip().split('\n')
95
- for line in lines:
96
- if "предмет:" in line:
97
- subject = line.split("предмет:")[1].strip().capitalize()
98
- elif "учебник:" in line:
99
- textbook = line.split("учебник:")[1].strip().capitalize()
100
-
101
- return subject, textbook
102
-
103
-
104
- # 10. Инициализация состояний
105
- if "textbook_data" not in st.session_state:
106
- st.session_state.textbook_data = TextbookInfo()
107
- if "image_url" not in st.session_state:
108
- st.session_state.image_url = None
109
- if "form_values" not in st.session_state:
110
- st.session_state.form_values = {
111
- field: config["default"]
112
- for field, config in FORM_CONFIG["main_fields"].items()
113
- }
114
- if "force_form_update" not in st.session_state:
115
- st.session_state.force_form_update = True
116
-
117
- # 11. Основной интерфейс
118
- left_col, right_col = st.columns([2, 3])
119
-
120
- with left_col:
121
- st.header("Настройки")
122
- AUTO_DETECT_ENABLED = st.toggle(
123
- "Автоматическое распознавание учебника",
124
- value=True,
125
- key="auto_detect_toggle"
126
- )
127
- st.header("Загрузка учебника")
128
- uploaded_file = st.file_uploader("Выберите изображение страницы", type=["jpg", "png", "jpeg"])
129
-
130
- # Обработка загрузки изображения
131
- if uploaded_file and not st.session_state.image_url:
132
- image_url = upload_to_catbox(uploaded_file.getvalue())
133
- if image_url:
134
- st.session_state.image_url = image_url
135
- st.success("Изображение загружено!")
136
-
137
- if AUTO_DETECT_ENABLED: # Только если включено
138
- with st.spinner("Анализ изображения..."):
139
- try:
140
- response = client.chat.completions.create(
141
- model="gpt-4o-mini",
142
- messages=[
143
- {
144
- "role": "user",
145
- "content": [
146
- {"type": "image_url", "image_url": {"url": image_url}},
147
- {"type": "text", "text": """Определи предмет и учебник. Ответь строго в формате:
148
- Предмет: [название]
149
- Учебник: [название]"""}
150
- ]
151
- }
152
- ]
153
- )
154
-
155
- if response.choices:
156
- subject, textbook = parse_response(response.choices[0].message.content)
157
- st.session_state.textbook_data = TextbookInfo(
158
- subject=subject,
159
- textbook_name=textbook
160
- )
161
- st.session_state.force_form_update = True
162
-
163
- except Exception as e:
164
- logger.error(f"Ошибка анализа: {e}")
165
- st.error("Ошибка при анализе изображения")
166
- else:
167
- st.info("Автораспознавание отключено. Заполните данные вручную")
168
- st.session_state.textbook_data = TextbookInfo()
169
- st.session_state.force_form_update = True
170
-
171
- # Форма с настройками
172
- if st.session_state.image_url:
173
- st.subheader("Данные учебника")
174
-
175
- # Обновление значений формы при необходимости
176
- if st.session_state.force_form_update:
177
- st.session_state.form_values.update({
178
- "subject": st.session_state.textbook_data.subject,
179
- "textbook": st.session_state.textbook_data.textbook_name
180
- })
181
- st.session_state.force_form_update = False
182
-
183
- with st.form(key="lesson_form"):
184
- # Динамическое создание полей из конфига
185
- for field, config in FORM_CONFIG["main_fields"].items():
186
- if config["type"] == "text":
187
- st.session_state.form_values[field] = st.text_input(
188
- config["label"],
189
- value=st.session_state.form_values[field],
190
- key=f"form_{field}"
191
- )
192
- elif config["type"] == "slider":
193
- st.session_state.form_values[field] = st.slider(
194
- config["label"],
195
- min_value=config["min"],
196
- max_value=config["max"],
197
- value=st.session_state.form_values[field],
198
- key=f"form_{field}"
199
- )
200
- elif config["type"] == "selectbox":
201
- st.session_state.form_values[field] = st.selectbox(
202
- config["label"],
203
- options=config["options"],
204
- index=config["options"].index(st.session_state.form_values[field]),
205
- key=f"form_{field}"
206
- )
207
-
208
- submitted = st.form_submit_button("Создать план урока")
209
-
210
- if submitted:
211
- if not st.session_state.form_values["subject"] or not st.session_state.form_values["textbook"]:
212
- st.warning("Заполните все обязательные поля")
213
- else:
214
- with st.spinner("Генерация плана урока..."):
215
- try:
216
- response = client.chat.completions.create(
217
- model="gpt-4o-mini",
218
- messages=[
219
- {
220
- "role": "system",
221
- "content": "Ты опытный учитель. Создай детальный план урока."
222
- },
223
- {
224
- "role": "user",
225
- "content": [
226
- {"type": "image_url", "image_url": {"url": st.session_state.image_url}},
227
- {"type": "text", "text": f"""
228
- Создай план урока по методике {st.session_state.form_values['methodology']}
229
- Детали:
230
- - Предмет: {st.session_state.form_values['subject']}
231
- - Учебник: {st.session_state.form_values['textbook']}
232
- - Учеников: {st.session_state.form_values['students']}
233
- """}
234
- ]
235
- }
236
- ]
237
- )
238
- right_col.markdown(response.choices[0].message.content)
239
- except Exception as e:
240
- st.error(f"Ошибка генерации: {e}")
241
-
242
- with right_col:
243
- st.header("План урока")
244
- if not st.session_state.image_url:
245
- st.info("Загрузите изображение учебника")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/test_gradio.py CHANGED
@@ -9,6 +9,8 @@ from docx import Document
9
  import requests
10
  from typing import Optional
11
 
 
 
12
  # --- Настройка ---
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
14
  load_dotenv()
@@ -59,6 +61,7 @@ def generate_lesson_plan(
59
  duration: int,
60
  inventory: str,
61
  methodology: str,
 
62
  hw_required: bool,
63
  web_search: bool,
64
  repetition: bool,
@@ -93,6 +96,7 @@ def generate_lesson_plan(
93
  f"- **Длительность**: {duration} минут",
94
  f"- **Инвентарь**: {inventory if inventory else 'стандартный'}",
95
  f"- **Методика**: {methodology}",
 
96
  # f"- **Таксономия**: {', '.join([level for level, checked in [('Повторение', repetition),
97
  # ('Применение', application),
98
  # ('Анализ', analysis),
@@ -130,7 +134,7 @@ def generate_lesson_plan(
130
  # Вызов LLM
131
  try:
132
  response = client.responses.create(
133
- instructions="Ты эксперт-педагог. Составь детальный план урока по заданным параметрам и изображению страницы учебника.",
134
  input=[{"role": "user", "content": input_content}],
135
  model="gpt-4o-mini",
136
  tools=tools or None,
 
9
  import requests
10
  from typing import Optional
11
 
12
+ import app.instructions
13
+
14
  # --- Настройка ---
15
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
  load_dotenv()
 
61
  duration: int,
62
  inventory: str,
63
  methodology: str,
64
+ extra_info: str,
65
  hw_required: bool,
66
  web_search: bool,
67
  repetition: bool,
 
96
  f"- **Длительность**: {duration} минут",
97
  f"- **Инвентарь**: {inventory if inventory else 'стандартный'}",
98
  f"- **Методика**: {methodology}",
99
+ # f"- **Дополнительная информация**: {extra_info}"
100
  # f"- **Таксономия**: {', '.join([level for level, checked in [('Повторение', repetition),
101
  # ('Применение', application),
102
  # ('Анализ', analysis),
 
134
  # Вызов LLM
135
  try:
136
  response = client.responses.create(
137
+ instructions=app.instructions.INSTRUCTIONS_1,
138
  input=[{"role": "user", "content": input_content}],
139
  model="gpt-4o-mini",
140
  tools=tools or None,
app/test_gradio_test.py ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import tempfile
4
+ from datetime import datetime
5
+ from dotenv import load_dotenv
6
+ from openai import OpenAI
7
+ import gradio as gr
8
+ from docx import Document
9
+ import requests
10
+ from typing import Optional
11
+
12
+ import app.instructions
13
+
14
+ # --- Настройка ---
15
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
+ load_dotenv()
17
+ api_key = os.getenv("API_KEY_openai")
18
+ client = OpenAI(api_key=api_key) if api_key else None
19
+ VS_ID = os.getenv("VECTOR_STORE_ID", "") # vector store for file_search if needed
20
+
21
+ # --- Утилиты ---
22
+ def upload_to_catbox(file_bytes: bytes) -> str:
23
+ """Загружает файл на catbox.moe и возвращает URL"""
24
+ try:
25
+ response = requests.post(
26
+ "https://catbox.moe/user/api.php",
27
+ files={"fileToUpload": file_bytes},
28
+ data={"reqtype": "fileupload"},
29
+ timeout=10
30
+ )
31
+ response.raise_for_status()
32
+ return response.text.strip()
33
+ except Exception as e:
34
+ logging.error(f"Ошибка загрузки изображения: {e}")
35
+ raise gr.Error("Не удалось загрузить изображение")
36
+
37
+
38
+ def generate_docx(text: str) -> str:
39
+ """Сохраняет текст в .docx и возвращает путь"""
40
+ doc = Document()
41
+ for line in text.split("\n"):
42
+ doc.add_paragraph(line)
43
+ tmp = tempfile.gettempdir()
44
+ path = os.path.join(tmp, f"lesson_plan_{datetime.now().strftime('%Y%m%d%H%M%S')}.docx")
45
+ doc.save(path)
46
+ return path
47
+
48
+ all_inputs = [
49
+ image, # Gradio компонент, соответствует image_path в функциях
50
+ textbook,
51
+ cefr,
52
+ topic,
53
+ goal,
54
+ format_type,
55
+ num_students,
56
+ age,
57
+ adults,
58
+ level_match,
59
+ duration,
60
+ inventory,
61
+ methodology,
62
+ hw_required,
63
+ web_search,
64
+ repetition,
65
+ application,
66
+ analysis,
67
+ creativity
68
+ ]
69
+ # --- Основная функция генерации ---
70
+ def generate_lesson_plan(
71
+ image_path: Optional[str],
72
+ textbook: str,
73
+ cefr: str,
74
+ topic: str,
75
+ goal: str,
76
+ format_type: str,
77
+ num_students: int,
78
+ age: str,
79
+ adults: bool,
80
+ level_match: int,
81
+ duration: int,
82
+ inventory: str,
83
+ methodology: str,
84
+ hw_required: bool,
85
+ web_search: bool,
86
+ repetition: bool,
87
+ application: bool,
88
+ analysis: bool,
89
+ creativity: bool
90
+ ) -> str:
91
+
92
+ # Валидация API клиента
93
+ if not client:
94
+ raise gr.Error("API ключ не настроен")
95
+ # Проверка наличия изображения
96
+ if not image_path:
97
+ return "❗ Загрузите фото страницы учебника для генерации урока"
98
+
99
+ # Загружаем изображение и получаем URL
100
+ try:
101
+ with open(image_path, "rb") as f:
102
+ image_url = upload_to_catbox(f.read())
103
+ except Exception as e:
104
+ logging.error(f"Image upload error: {e}")
105
+ raise gr.Error("Не удалось загрузить изображение")
106
+
107
+ # Собираем текстовый prompt
108
+ lesson_params = {
109
+ 'methodology': methodology,
110
+ 'Учебник': textbook,
111
+ 'Уровень учебника по CEFR': cefr,
112
+ 'Тема': topic,
113
+ 'Цель': goal,
114
+ 'Количество учеников': num_students,
115
+ 'Возраст': 'Взрослые' if adults else age,
116
+ 'level_match': ['below', 'on-level', 'above', 'mixed'][level_match],
117
+ 'duration': duration,
118
+ 'inventory': inventory,
119
+ 'hw_required': hw_required
120
+ }
121
+
122
+ # Получаем готовый промпт
123
+ from app.prompt_builder.prompt import build_prompt
124
+ full_prompt = build_prompt(lesson_params)
125
+
126
+ # Собираем входные данные согласно API
127
+ input_content = [
128
+ {
129
+ "type": "input_text",
130
+ "text": full_prompt
131
+ },
132
+ {
133
+ "type": "input_image",
134
+ "image_url": image_url,
135
+ "detail": "high"
136
+ }
137
+ ]
138
+
139
+ # Опции инструментов
140
+ tools = []
141
+ tool_choice = None
142
+ if web_search:
143
+ tools.append({
144
+ "type": "web_search_preview",
145
+ "search_context_size": "medium",
146
+ "user_location": {"type": "approximate", "country": "RU"}
147
+ })
148
+ tool_choice = {"type": "web_search_preview"}
149
+
150
+ # Вызов LLM
151
+ try:
152
+ response = client.responses.create(
153
+ input=input_content,
154
+ model="gpt-4o-mini",
155
+ tools=tools or None,
156
+ tool_choice=tool_choice,
157
+ max_output_tokens=2000,
158
+ stream=False
159
+ )
160
+ return response.output_text
161
+
162
+ except Exception as e:
163
+ logging.error(f"Generation error: {e}")
164
+ raise gr.Error(f"Ошибка генерации: {e}")
165
+
166
+
167
+ # --- Gradio UI ---
168
+ with gr.Blocks(title="AI-Генератор уроков по фото учебника") as app:
169
+ advanced_settings_visible = gr.State(False) # Добавляем состояние для видимости блока
170
+ with gr.Row():
171
+ with gr.Column(scale=1): # левый блок
172
+ image = gr.Image(label="Фото страницы учебника*", type="filepath")
173
+
174
+ # Блок 1: Учебник
175
+ with gr.Column(variant="panel"):
176
+ gr.Markdown("### 📚 Учебник", elem_classes=["block-title"])
177
+ textbook = gr.Textbox(label="Название учебника", placeholder="English File Beginner")
178
+ cefr = gr.Dropdown(label="CEFR-уровень", choices=["", "A1", "A2", "B1", "B2", "C1", "C2"],
179
+ value="", info="Выберите уровень")
180
+
181
+ # Блок 2: Класс
182
+ with gr.Column(variant="panel"):
183
+ gr.Markdown("### 👥 Класс", elem_classes=["block-title"])
184
+ format_type = gr.Radio(label="Формат занятия*", choices=["Индивидуальное", "Групповое"],
185
+ value="Групповое")
186
+
187
+ with gr.Group(visible=True) as group_settings:
188
+ num_students = gr.Slider(label="Количество учеников*", minimum=1, maximum=40,
189
+ value=10, step=1, info="Для групповых занятий")
190
+
191
+ with gr.Group() as age_group:
192
+ adults = gr.Checkbox(label="Взрослые")
193
+ age = gr.Textbox(label="Возраст*", placeholder="10–11", interactive=True)
194
+
195
+ level_match = gr.Slider(label="Соответствие уровня учебника", minimum=0, maximum=3,
196
+ step=1, value=1, info="0=ниже,1=соответствует,2=выше,3=смешанный")
197
+
198
+ # Блок 3: Занятие
199
+ with gr.Column(variant="panel"):
200
+ gr.Markdown("### 📄 Занятие", elem_classes=["block-title"])
201
+ topic = gr.Textbox(label="Тема", placeholder="Daily routines")
202
+ goal = gr.Textbox(label="Цель", placeholder="Практика Present Simple")
203
+ duration = gr.Slider(label="Длительность (мин)*", minimum=30, maximum=180, value=60, step=5)
204
+ inventory = gr.Textbox(label="Инвентарь", placeholder="Карточки, проектор...")
205
+
206
+ # Блок 4: Методика
207
+ with gr.Column(variant="panel"):
208
+ gr.Markdown("### 🎓 Методика", elem_classes=["block-title"])
209
+ methodology = gr.Dropdown(label="Методика преподавания*",
210
+ choices=["PPP (Presentation-Practice-Production)",
211
+ "TTT (Test-Teach-Test)"],
212
+ value="PPP (Presentation-Practice-Production)")
213
+
214
+ advanced_btn = gr.Button(value="➕ Продвинутые настройки", size="sm")
215
+
216
+ # Блок продвинутых настроек, изначально скрыт
217
+ with gr.Column(visible=False) as advanced_block:
218
+ gr.Markdown("**💡 Уровни задач (таксономия):**")
219
+ repetition = gr.Checkbox(label="Повторение")
220
+ application = gr.Checkbox(label="Применение")
221
+ analysis = gr.Checkbox(label="Анализ")
222
+ creativity = gr.Checkbox(label="Творчество")
223
+
224
+ hw_required = gr.Checkbox(label="Домашнее задание")
225
+ web_search = gr.Checkbox(label="Доп. материалы из интернета")
226
+
227
+ btn = gr.Button("Сгенерировать план", variant="primary", size="lg")
228
+
229
+ with gr.Column(scale=2): # правый блок
230
+ output = gr.Markdown("## План урока появится здесь...")
231
+ download_btn = gr.DownloadButton(label="⬇️ Скачать .docx", visible=False)
232
+
233
+
234
+
235
+ # --- Логика интерфейса ---
236
+ def toggle_advanced_settings(visible):
237
+ return gr.update(visible=not visible), not visible
238
+
239
+
240
+ advanced_btn.click(
241
+ fn=toggle_advanced_settings,
242
+ inputs=[advanced_settings_visible],
243
+ outputs=[advanced_block, advanced_settings_visible]
244
+ )
245
+
246
+ # Функция для переключения видимости полей в зависимости от формата занятия
247
+ def toggle_format(selected_format):
248
+ return gr.update(visible=selected_format == "Групповое")
249
+ format_type.change(fn=toggle_format, inputs=format_type, outputs=group_settings)
250
+
251
+ # Функция для переключения поля возраста
252
+ def toggle_age(adult_checked):
253
+ return gr.update(interactive=not adult_checked)
254
+ adults.change(fn=toggle_age, inputs=adults, outputs=age)
255
+
256
+
257
+ # Коллбек генерации
258
+ def on_generate(
259
+ image_path: Optional[str], # Переименовано из image
260
+ textbook: str,
261
+ cefr: str,
262
+ topic: str,
263
+ goal: str,
264
+ format_type: str,
265
+ num_students: int,
266
+ age: str,
267
+ adults: bool,
268
+ level_match: int,
269
+ duration: int,
270
+ inventory: str,
271
+ methodology: str,
272
+ hw_required: bool,
273
+ web_search: bool,
274
+ repetition: bool,
275
+ application: bool,
276
+ analysis: bool,
277
+ creativity: bool
278
+ ):
279
+ # Проверка обязательных полей
280
+ if not image_path or (not adults and not age):
281
+ return gr.update(value="❗ Заполните обязательные поля (отмечены *)"), gr.update(visible=False)
282
+
283
+ # Собираем все аргументы в словарь
284
+ kwargs = locals()
285
+
286
+ # Генерация плана
287
+ text = generate_lesson_plan(**kwargs)
288
+
289
+ # Создание DOCX
290
+ docx_path = generate_docx(text) if not text.startswith("❗") else None
291
+ return gr.update(value=text), gr.update(visible=bool(docx_path), value=docx_path)
292
+
293
+ btn.click(
294
+ fn=on_generate,
295
+ inputs=all_inputs,
296
+ outputs=[output, download_btn]
297
+ )
298
+
299
+ if __name__ == "__main__":
300
+ app.launch()
docs/architecture.md CHANGED
@@ -28,6 +28,17 @@
28
 
29
 
30
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
 
33
 
 
28
 
29
 
30
 
31
+ Собираем все параметры в all_inputs (это список Gradio-компонентов).
32
+
33
+ Передаём их в on_generate через inputs=all_inputs.
34
+
35
+ Внутри on_generate используем locals(), чтобы автоматически получить словарь всех аргументов.
36
+
37
+ Распаковываем их в generate_lesson_plan(**kwargs).
38
+
39
+
40
+
41
+
42
 
43
 
44