Nefertury commited on
Commit
a543854
·
verified ·
1 Parent(s): 7b9122c

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +426 -0
app.py ADDED
@@ -0,0 +1,426 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import json
4
+ import gradio as gr
5
+ import pandas as pd
6
+ import matplotlib.pyplot as plt
7
+ import pypdf
8
+ import warnings
9
+ from google.colab import userdata
10
+ from langchain_google_genai import ChatGoogleGenerativeAI
11
+
12
+ warnings.filterwarnings("ignore", category=UserWarning)
13
+ print("--- Библиотеки установлены и импортированы ---")
14
+
15
+
16
+ # --- 2. Настройка API и LLM ---
17
+ print("--- Настройка API и LLM ---")
18
+ try:
19
+ GEMINI_API_KEY = userdata.get('GEMINI_API_KEY')
20
+ API_BASE_URL = "http://194.113.209.48:8000"
21
+ llm = ChatGoogleGenerativeAI(model="gemini-1.5-pro-latest", google_api_key=GEMINI_API_KEY, temperature=0.1)
22
+ print("✅ LLM настроена.")
23
+ except Exception as e:
24
+ print(f"❌ Ошибка настройки LLM: {e}")
25
+
26
+
27
+ # --- 3. Загрузка данных и контекста ---
28
+ # 3.1. Загружаем заранее проанализированный портфель из CSV
29
+ print("--- Загрузка данных портфеля ---")
30
+ try:
31
+ tagged_portfolio_df = pd.read_csv('sber_portfolio_analyzed5.csv')
32
+ tagged_portfolio_df['region_name'] = tagged_portfolio_df['region_name'].str.strip()
33
+ print(f"✅ Успешно загружен проанализированный портфель из {len(tagged_portfolio_df)} проектов.")
34
+ except FileNotFoundError:
35
+ print("❌ Ошибка: Файл 'sber_portfolio_analyzed5.csv' не найден. Возможно, нужно сначала запустить ячейку для генерации этого файла.")
36
+ tagged_portfolio_df = pd.DataFrame()
37
+
38
+ # 3.2. Извлекаем текст из PDF-отчета
39
+ print("--- Извлечение текста из PDF-отчета ---")
40
+ full_report_text = ""
41
+ try:
42
+ # Убедитесь, что имя файла верное и он загружен
43
+ with open('f356d44202ac9361579f509ebf965950.pdf', 'rb') as f:
44
+ reader = pypdf.PdfReader(f)
45
+ for page in reader.pages:
46
+ full_report_text += page.extract_text() + "\n"
47
+ print("✅ Текст из PDF-файла успешно извлечен.")
48
+ except Exception as e:
49
+ print(f"❌ Ошибка при чтении PDF-файла: {e}")
50
+
51
+ # 3.3. Загружаем справочники
52
+ print("--- Загрузка справочников ---")
53
+ try:
54
+ regions_response = requests.get(f"{API_BASE_URL}/api/regions")
55
+ regions_data = regions_response.json()
56
+ regions_list = sorted([item['name'] for item in regions_data])
57
+ print("✅ Справочник регионов загружен.")
58
+ except Exception as e:
59
+ print(f"❌ Не удалось загрузить справочник регионов: {e}")
60
+ regions_list = sorted(list(tagged_portfolio_df['region_name'].unique()))
61
+
62
+ # 3.4. Определяем константы (структура Наццелей) - ПОЛНАЯ ВЕРСИЯ
63
+ NATIONAL_GOALS_STRUCTURE = {
64
+ "Сохранение населения, укрепление здоровья и повышение благополучия людей, поддержка семьи": [
65
+ "2.а) повышение суммарного коэффициента рождаемости до 1,6 к 2030 году и до 1,8 к 2036 году",
66
+ "2.б) увеличение ожидаемой продолжительности жизни до 78 лет к 2030 году и до 81 года к 2036 году",
67
+ "2.в) обеспечение не ниже среднероссийских темпов повышения к 2030 году суммарного коэффициента рождаемости в отстающих субъектах РФ",
68
+ "2.г) снижение к 2036 году дифференциации показателей ожидаемой продолжительности жизни не менее чем на 25%",
69
+ "2.д) снижение к 2030 году суммарной продолжительности временной нетрудоспособности граждан",
70
+ "2.е) повышение к 2030 году уровня удовлетворенности граждан условиями для занятий физкультурой и спортом",
71
+ "2.ж) увеличение к 2030 году численности граждан, получающих услуги долговременного ухода, до 500 тыс. человек",
72
+ "2.з) повышение к 2030 году уровня удовлетворенности участников СВО условиями для медицинской реабилитации и трудоустройства",
73
+ "2.и) создание и запуск к 2030 году цифровой платформы по управлению здоровьем человека",
74
+ "2.к) снижение уровн�� бедности ниже 7% к 2030 году и ниже 5% к 2036 году, в т.ч. среди многодетных семей",
75
+ "2.л) снижение коэффициента Джини до 0,37 к 2030 году и до 0,33 к 2036 году",
76
+ "2.м) рост МРОТ к 2030 году более чем в два раза, не менее 35 тыс. рублей в месяц",
77
+ "2.н) утверждение в 2026 году новых систем оплаты труда работников бюджетной сферы"
78
+ ],
79
+ "Реализация потенциала каждого человека, развитие его талантов, воспитание патриотичной и социально ответственной личности": [
80
+ "3.а) создание к 2030 году условий для воспитания гармонично развитой личности на основе традиционных ценностей",
81
+ "3.б) увеличение к 2030 году численности иностранных студентов до 500 тыс. человек",
82
+ "3.в) увеличение к 2030 году доли молодых людей, участвующих в проектах развития и воспитания, до 75%",
83
+ "3.г) увеличение к 2030 году доли молодых людей, верящих в самореализацию в России, до 85%",
84
+ "3.д) увеличение к 2030 году доли молодых людей в добровольческой деятельности до 45%",
85
+ "3.е) обеспечение к 2030 году функционирования эффективной системы выявления талантов у 100% обучающихся",
86
+ "3.ж) обеспечение продвижения традиционных ценностей в не менее чем 70% проектов в сфере культуры к 2030 году",
87
+ "3.з) повышение к 2030 году удовлетворенности граждан работой организаций культуры",
88
+ "3.и) формирование к 2030 году современной системы профразвития педагогических работников"
89
+ ],
90
+ "Комфортная и безопасная среда для жизни": [
91
+ "4.а) улучшение качества среды для жизни в опорных населенных пунктах на 30% к 2030 году",
92
+ "4.б) обеспечение граждан жильем общей площадью не менее 33 кв. метров на человека к 2030 году",
93
+ "4.в) обновление к 2030 году жилищного фонда не менее чем на 20% по сравнению с 2019 годом",
94
+ "4.г) устойчивое сокращение непригодного для проживания жилищного фонда",
95
+ "4.д) повышение доступности жилья на первичном рынке",
96
+ "4.е) благоустройство не менее чем 30 тыс. общественных территорий к 2030 году",
97
+ "4.ж) реализация программы модернизации коммунальной инфраструктуры для 20 млн. человек к 2030 году",
98
+ "4.з) строительство и реконструкция не менее чем 2 тыс. объектов питьевого водоснабжения к 2030 году",
99
+ "4.и) рост энергоэффективности в ЖКХ и строительстве",
100
+ "4.к) обновление парка общественного транспорта до 85% от норматива к 2030 году",
101
+ "4.л) приведение в нормативное состояние 85% дорог агломераций и 60% региональных дорог к 2030 году",
102
+ "4.м) снижение смертности в ДТП в 1.5 раза к 2030 году",
103
+ "4.н) увеличение авиационной подвижности населения на 50% к 2030 году",
104
+ "4.о) капитальный ремонт всех нуждающихся зданий школ и детсадов до конца 2030 года",
105
+ "4.п) подключение к сетевому газу не менее 1,6 млн домовладений к 2030 году",
106
+ "4.р) оснащение 900 центров кинопоказа в малых населенных пунктах к 2030 году"
107
+ ],
108
+ "Экологическое благополучие": [
109
+ "5.а) формирование экономики замкнутого цикла: 100% сортировка ТКО, захоронение не более 50%, вовлечение 25% отходов в оборот к 2030 году",
110
+ "5.б) снижение в два раза выбросов опасных загрязняющих веществ в городах с высоким уровнем загрязнения к 2036 году",
111
+ "5.в) ликвидация до конца 2030 года не менее 50 опасных объектов накопленного вреда",
112
+ "5.г) снижение к 2036 году в два раза объема неочищенных сточных вод",
113
+ "5.д) сохранение лесов, биоразнообразия и создание условий для экологического туризма"
114
+ ],
115
+ "Устойчивая и динамичная экономика": [
116
+ "6.а) темп роста ВВП выше среднемирового, 4-е место в мире по ВВП по ППС к 2030 году",
117
+ "6.б) снижение доли импорта до 17% ВВП к 2030 году",
118
+ "6.в) увеличение объема инвестиций в основной капитал на 60% к 2030 году (относительно 2020)",
119
+ "6.г) рост доходов населения и пенсий не ниже уровня инфляции",
120
+ "6.д) реальный рост дохода на работника МСП в 1,2 раза выше роста ВВП",
121
+ "6.ж) вхождение в топ-25 стран мира по плотности роботизации к 2030 году",
122
+ "6.н) увеличение доли туристской отрасли в ВВП до 5% к 2030 году",
123
+ "6.о) прирост экспорта несырьевых неэнергетических товаров на две трети к 2030 году",
124
+ "6.п) увеличение производства продукции АПК на 25% к 2030 году (относительно 2021)",
125
+ "6.р) увеличение экспорта продукции АПК в 1.5 раза к 2030 году (относительно 2021)"
126
+ ],
127
+ "Технологическое лидерство": [
128
+ "7.а) обеспечение технологической независимости (биоэкономика, БАС, ИИ, новые материалы и др.)",
129
+ "7.б) увеличение индекса производства в обрабатывающей промышленности на 40% к 2030 году (относительно 2022)",
130
+ "7.в) вхождение в топ-10 стран мира по объему научных исследований к 2030 году",
131
+ "7.г) увеличение внутренних затрат на исследования до 2% ВВП к 2030 году",
132
+ "7.д) увеличение доли отечественных высокотехнологичных товаров в 1.5 раза к 2030 году",
133
+ "7.е) увеличение выручки малых технологических компаний в 7 раз к 2030 году"
134
+ ],
135
+ "Цифровая трансформация": [
136
+ "8.а) достижение 'цифровой зрелости' госуправления и ключевых отраслей экономики к 2030 году",
137
+ "8.б) формирование рынка данных",
138
+ "8.в) доступ к высокоскоростному интернету для 97% домохозяйств к 2030 году",
139
+ "8.г) рост инвестиций в отечественные ИТ-решения вдвое выше темпа роста ВВП",
140
+ "8.д) переход 80% организаций на российское ПО к 2030 году"
141
+ ]
142
+ }
143
+ print("✅ Словарь НАЦЦЕЛЕЙ успешно загружен.")
144
+
145
+ # --- 4. Определение функций приложения ---
146
+ print("--- Определение функций приложения ---")
147
+ # (Здесь идут полные определения функций generate_regional_briefing, _find_relevant_goals, analyze_new_project)
148
+ # --- ФИНАЛЬНАЯ ВЕРСИЯ С ТАБЛИЧНЫМ ПРЕДСТАВЛЕНИЕМ АНАЛИЗА ---
149
+
150
+ def generate_regional_briefing(region_name, year):
151
+ if not region_name or not year:
152
+ yield "Пожалуйста, выберите регион и год.", None, None
153
+ return
154
+
155
+ if not 'full_report_text' in globals() or not full_report_text:
156
+ yield "Ошибка: Текст отчета ESG-индекса не был загружен.", None, None
157
+ return
158
+
159
+ yield "<h3 style='margin-top: 20px;'>⏳ Готовлю финальный отчет, это может занять до 30 секунд...</h3>", None, None
160
+
161
+ try:
162
+ region_id = next((item['id'] for item in regions_data if item['name'] == region_name), None)
163
+ params = {"year": int(year)}
164
+ response = requests.get(f"{API_BASE_URL}/api/region-performance/{region_id}/all", params=params)
165
+ response.raise_for_status()
166
+ urfu_data_raw = response.json()
167
+ urfu_data_simplified = {indicator.get('name'): indicator.get('region_value') for indicator in urfu_data_raw.get('indicators', []) if indicator.get('name') and indicator.get('region_value') is not None}
168
+ except Exception as e:
169
+ yield f"Не удалось получить данные от API УрФУ. Ошибка: {e}", None, None
170
+ return
171
+
172
+ region_portfolio = tagged_portfolio_df[tagged_portfolio_df['region_name'] == region_name]
173
+
174
+ portfolio_summary = "В данном регионе у Сбера отсутствуют проекты из анализируемого портфеля."
175
+ fig = None
176
+
177
+ if not region_portfolio.empty:
178
+ total_investment = region_portfolio['amount_bln_rub'].sum()
179
+ project_count = len(region_portfolio)
180
+ SUMMARIZATION_THRESHOLD = 5
181
+
182
+ if 'mapped_goal' in region_portfolio.columns and not region_portfolio['mapped_goal'].isnull().all():
183
+ if project_count > SUMMARIZATION_THRESHOLD:
184
+ summary_parts = []
185
+ goal_groups = region_portfolio.groupby('mapped_goal')['amount_bln_rub'].sum().sort_values(ascending=False).reset_index()
186
+
187
+ for _, row in goal_groups.iterrows():
188
+ goal_name = row['mapped_goal']
189
+ goal_sum = row['amount_bln_rub']
190
+ project_examples = region_portfolio[region_portfolio['mapped_goal'] == goal_name]['project_goal'].head(2).tolist()
191
+ examples_text = ", ".join(project_examples)
192
+ # ИЗМЕНЕНИЕ: Формируем HTML-элемент списка <li> и используем <strong> для жирности
193
+ summary_parts.append(
194
+ f"<li><strong>{goal_name}</strong> ({goal_sum:.1f} млрд руб.), ключевые проекты: {examples_text}</li>"
195
+ )
196
+
197
+ # ИЗМЕНЕНИЕ: Собираем полный HTML-список <ul>...</ul>
198
+ summary_text = "<ul>" + "".join(summary_parts) + "</ul>"
199
+ portfolio_summary = (
200
+ f"Портфель Сбера в регионе составляет {total_investment:.1f} млрд руб. и включает проекты, распределенные по следующим национальным целям:{summary_text}"
201
+ )
202
+ else:
203
+ projects_list = [
204
+ f"'{row['project_goal']}' ({row['amount_bln_rub']:.1f} млрд руб.), направленный на достижение цели \"{row.get('mapped_goal', 'не определена')}\""
205
+ for _, row in region_portfolio.iterrows()
206
+ ]
207
+ projects_text = " и ".join(projects_list)
208
+ portfolio_summary = (
209
+ f"Текущий портфель Сбера в регионе составляет {total_investment:.1f} млрд руб. "
210
+ f"и включает следующие ключевые проекты: {projects_text}."
211
+ )
212
+ else:
213
+ projects_list = [
214
+ f"'{row['project_goal']}' ({row['amount_bln_rub']:.1f} млрд руб.)"
215
+ for _, row in region_portfolio.iterrows()
216
+ ]
217
+ projects_text = ", ".join(projects_list)
218
+ portfolio_summary = (
219
+ f"Текущий портфель Сбера в регионе составляет {total_investment:.1f} млрд руб. и включает следующие проекты: {projects_text}."
220
+ )
221
+
222
+ if 'mapped_goal' in region_portfolio.columns and not region_portfolio['mapped_goal'].isnull().all():
223
+ goal_distribution = region_portfolio.groupby('mapped_goal')['amount_bln_rub'].sum()
224
+ plot_data = goal_distribution.reset_index()
225
+ if plot_data is not None and not plot_data.empty:
226
+ fig, ax = plt.subplots(figsize=(10, 6)); bars = ax.bar(plot_data['mapped_goal'], plot_data['amount_bln_rub'], color='#4CAF50'); ax.bar_label(bars, fmt='%.0f', padding=3)
227
+ plt.xticks(rotation=45, ha="right", fontsize=9); plt.title(f"Распределение портфеля Сбера по Наццелям\nв регионе: {region_name}", fontsize=12)
228
+ plt.ylabel("Сумма, млрд руб.", fontsize=10); plt.grid(axis='y', linestyle='--', alpha=0.7); plt.tight_layout()
229
+
230
+ prompt = f"""
231
+ Твоя роль: Ведущий аналитик-стратег ESG-дирекции Сбера.
232
+ Твоя задача: Подготовить исчер��ывающий и СТРУКТУРИРОВАННЫЙ аналитический отчет по региону, синтезируя информацию из предоставленных источников.
233
+
234
+ ### ИСТОЧНИК 1: Статистические показатели по региону (от УрФУ)
235
+ Регион анализа: {region_name}
236
+ {json.dumps(urfu_data_simplified, ensure_ascii=False, indent=2)}
237
+
238
+ ### ИСТОЧНИК 2: Полный текст отчета "ESG-индекс городов и регионов" (Сбер, ВЭБ.РФ)
239
+ ```text
240
+ {full_report_text}
241
+ ```
242
+
243
+ ### ИСТОЧНИК 3: Данные по проектам в регионе
244
+ {portfolio_summary}
245
+
246
+ ### ЗАДАЧА И СТРОГИЕ ПРАВИЛА:
247
+ 1. Подготовь отчет в формате Markdown.
248
+ 2. Сфокусируй детальный анализ ТОЛЬКО на двух Национальных целях: "Сохранение населения, укрепление здоровья и повышение благополучия людей, поддержка семьи" и "Комфортная и безопасная среда для жизни".
249
+ 3. Относись ко всем данным как к реальным, не добавляй дисклеймеров.
250
+ 4. Для раздела "Детальный анализ" **сгенерируй Markdown-таблицы**, как показано в шаблоне.
251
+
252
+ ---
253
+
254
+ ### Аналитический отчет: {region_name}, {year} год
255
+
256
+ **1. Обзор проектов в регионе**
257
+ * На основе ИСТОЧНИКА 3, опиши состав и объем проектов. Начинай с новой строки каждую новую Наццель и по ней проекты.
258
+
259
+ * **Задача для следующей строки:** На основе ИСТОЧНИКА 2, найди конкретные факты о регионе `{region_name}` (место в рейтинге, баллы, и т.д.).
260
+ * **Требование к форматированию:** Начни строку с "ESG-индекс городов и регионов Сбер - ВЭБ.РФ:". Сразу после этого, обычным черным текстом, продолжи своим аналитическим выводом.
261
+
262
+ **2. Детальный анализ по приоритетным Национальным целям**
263
+ * Для каждой из двух приоритетных Наццелей, создай подзаголовок и Markdown-таблицу по следующему образцу. Заполни 2-3 строки для каждой таблицы наиболее показательными данными.
264
+
265
+ **Национальная цель: "Сохранение населения, укрепление здоровья и повышение благополучия людей, поддержка семьи"**
266
+ | Показатель (данные УрФУ) | Значение в регионе | Влияние проектов Сбера |
267
+ | :--- | :--- | :--- |
268
+ | *[название показателя из ИСТОЧНИКА 1]* | *[значение из ИСТОЧНИКА 1]* | *[твой анализ ИСТОЧНИКА 3]* |
269
+ | *[название второго показателя]* | *[его значение]* | *[твой анализ]* |
270
+
271
+ **Национальная цель: "Комфортная и безопасная среда для жизни"**
272
+ | Показатель (данные УрФУ) | Значение в регионе | Влияние проектов Сбера |
273
+ | :--- | :--- | :--- |
274
+ | *[название показателя из ИСТОЧНИКА 1]* | *[значение из ИСТОЧНИКА 1]* | *[твой анализ ИСТОЧНИКА 3]* |
275
+ | *[название второго показателя]* | *[его значение]* | *[твой анализ]* |
276
+
277
+ **3. Стратегические рекомендации**
278
+ * На основе табличного анализа, сформулируй 2-3 ключевых вывода и предложи конкретные типы проектов для инвестиций.
279
+ """
280
+
281
+ final_report = llm.invoke(prompt).content
282
+ yield final_report, fig, region_portfolio.drop(columns=['project_goal'], errors='ignore')
283
+
284
+ def _find_relevant_goals(project_description: str) -> list:
285
+ top_level_goals = list(NATIONAL_GOALS_STRUCTURE.keys())
286
+ prompt = f"""
287
+ Определи 1-3 наиболее релевантных национальных цели из списка для проекта. Верни ТОЛЬКО JSON-массив строк.
288
+ СПИСОК НАЦЦЕЛЕЙ: {json.dumps(top_level_goals, ensure_ascii=False)}
289
+ ОПИСАНИЕ ПРОЕКТА: "{project_description}"
290
+ Твой JSON-ответ:
291
+ """
292
+ try:
293
+ response = llm.invoke(prompt)
294
+ return json.loads(response.content.strip().replace("```json", "").replace("```", ""))
295
+ except Exception:
296
+ return top_level_goals
297
+
298
+
299
+ def analyze_new_project(region_name, project_description):
300
+ if not all([region_name, project_description]):
301
+ yield "Пожалуйста, выберите регион и опишите проект."
302
+ return
303
+
304
+ yield "<h3 style='margin-top: 20px;'>⏳ Этап 1/2: Определяю релевантные наццели...</h3>"
305
+ relevant_goals_names = _find_relevant_goals(project_description)
306
+ relevant_goals_structure = {goal: NATIONAL_GOALS_STRUCTURE.get(goal, []) for goal in relevant_goals_names}
307
+
308
+ yield "<h3 style='margin-top: 20px;'>⏳ Этап 2/2: Готовлю детальный анализ, это может занять до 30 секунд...</h3>"
309
+
310
+ try:
311
+ region_id = next((item['id'] for item in regions_data if item['name'] == region_name), None)
312
+ params = {"year": 2024} # Можно использовать актуальный год
313
+ response = requests.get(f"{API_BASE_URL}/api/region-performance/{region_id}/all", params=params)
314
+ response.raise_for_status()
315
+ urfu_data_raw = response.json()
316
+ urfu_data_simplified = {indicator.get('name'): indicator.get('region_value') for indicator in urfu_data_raw.get('indicators', []) if indicator.get('name') and indicator.get('region_value') is not None}
317
+ except Exception as e:
318
+ yield f"Не удалось получить данные от API УрФУ. Ошибка: {e}"
319
+ return
320
+
321
+ goals_structure_str = json.dumps(relevant_goals_structure, ensure_ascii=False, indent=2)
322
+
323
+ # --- НАЧАЛО НОВОГО, РАСШИРЕННОГО ПРОМПТА ---
324
+ prompt = f"""
325
+ Твоя роль: Ведущий аналитик ESG-дирекции Сбера, обладающий глубокими знаниями в области национальных целей развития РФ.
326
+
327
+ Твоя задача: Подготовить ДЕТАЛЬНЫЙ и СТРУКТУРИРОВАННЫЙ аналитический отчет по новому инвестиционному проекту. Отчет должен быть выполнен в формате Markdown и содержать глубокий анализ, а не поверхностное описание.
328
+
329
+ ### ВХОДНЫЕ ДАННЫЕ:
330
+ 1. **Регион реализации:** {region_name}
331
+ 2. **Описание проекта:** "{project_description}"
332
+ 3. **Статистический контекст по региону (данные УрФУ):** {json.dumps(urfu_data_simplified, ensure_ascii=False, indent=2)}
333
+ 4. **Структура релевантных Национальных целей и их задач:** {goals_structure_str}
334
+
335
+ ### СТРОГИЕ ТРЕБОВАНИЯ К СТРУКТУРЕ И СОДЕРЖАНИЮ ОТЧЕТА:
336
+
337
+ **1. Краткое резюме проекта**
338
+ * Опиши суть проекта, его масштаб и основные цели.
339
+
340
+ **2. Анализ соответствия Национальным целям**
341
+ * Для КАЖДОЙ релевантной наццели из предоставленного списка:
342
+ * **Обоснуй, почему проект соответствует данной цели.** Четко свяжи деятельность по проекту с конкретными задачами (подпунктами) этой наццели.
343
+ * **Используй данные из статистического контекста (ВХОДНЫЕ ДАННЫЕ №3)**, чтобы показать АКТУАЛЬНОСТЬ проекта для региона. Например, если проект влияет на здравоохранение, приведи текущие показатели по ожидаемой продолжительности жизни или заболеваемости в регионе, чтобы подчеркнуть важность инвестиций.
344
+
345
+ **3. Оценка по ESG-критериям**
346
+ * **E (Environmental / Экология):** Оцени потенциальное положительное и отрицательное воздействие проекта на окружающую среду. Какие экологические риски и возможности он несет? (например, снижение выбросов, образование отходов, использование "зеленых" технологий).
347
+ * **S (Social / Социальная сфера):** Проанализируй социальный эффект. Создание рабочих мест (сколько, каких?), влияние на ка��ество жизни, доступность услуг, поддержка местных сообществ.
348
+ * **G (Governance / Управление):** Опиши потенциальные управленческие аспекты. Необходимость взаимодействия с региональными властями, прозрачность реализации, работа с заинтересованными сторонами.
349
+
350
+ **4. Предварительные риски и рекомендации**
351
+ * На основе всего анализа, выдели 2-3 ключевых риска (технологических, социальных, регуляторных), на которые стоит обратить внимание.
352
+ * Дай 1-2 стратегические рекомендации по усилению положительного эффекта от проекта.
353
+
354
+ **5. Итоговое заключение**
355
+ * Сделай общий вывод о стратегической привлекательности проекта для банка с точки зрения вклада в устойчивое развитие и национальные приоритеты.
356
+
357
+ ---
358
+ **Начинай твой отчет.**
359
+ """
360
+ # --- КОНЕЦ НОВОГО ПРОМПТА ---
361
+
362
+ analysis_report = llm.invoke(prompt).content
363
+ yield analysis_report
364
+
365
+
366
+ # --- 5. Запуск веб-интерфейса Gradio ---
367
+ print("🚀 Запускаем Gradio-приложение...")
368
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="green", secondary_hue="lime"), css=".gradio-container {background-color: #f5f5f5} th { white-space: nowrap; }") as demo:
369
+ gr.Markdown(
370
+ """<div style="text-align: center;"><img src="https://www.sberbank.com/common/img/uploaded/logo/logo_sber_main_2020_ru.svg" width="200">
371
+ <h1>Интерактивный дашборд "Горизонт PRO"</h1><p>Анализ вклада в достижение Национальных целей РФ 2030/2036</p></div>"""
372
+ )
373
+ with gr.Tabs():
374
+ with gr.TabItem("📈 Стратегический обзор региона"):
375
+ with gr.Row():
376
+ region_input_1 = gr.Dropdown(regions_list, label="Выберите регион")
377
+ year_input_1 = gr.Dropdown([2024, 2023, 2022], label="Выберите год", value=2024)
378
+ submit_button_1 = gr.Button("Сформировать стратегическую справку", variant="primary")
379
+ gr.Markdown("---")
380
+ output_report_1 = gr.Markdown(label="Аналитическая справка")
381
+
382
+ # Элементы создаются, но не отображаются в интерфейсе
383
+ # Это необходимо, чтобы функция click могла в них вернуть значения без ошибки.
384
+ output_plot_1 = gr.Plot(visible=False)
385
+ output_table_1 = gr.DataFrame(label="Проекты в портфеле", visible=False)
386
+
387
+
388
+ with gr.TabItem("🔎 Экспресс-оценка нового проекта"):
389
+ # --- ИЗМЕНЕНИЕ №1: Выносим текст примера в отдельную переменную ---
390
+ example_text = "Мусоросортировочный завод на 150 000 тонн стоимостью 3 млрд руб"
391
+
392
+ gr.Markdown("Введите описание нового инвестиционного проекта для анализа его соответствия Национальным целям и потребностям региона.")
393
+ region_input_2 = gr.Dropdown(regions_list, label="Выберите регион реализации проекта")
394
+ project_input_2 = gr.Textbox(lines=4, label="Опишите проект", placeholder=f"Пример: {example_text}")
395
+
396
+ # --- ИЗМЕНЕНИЕ №2: Добавляем две кнопки в одну строку ---
397
+ with gr.Row():
398
+ # Кнопка для вставки примера
399
+ example_button = gr.Button("✍️ Вставить пример", variant="secondary")
400
+ # Основная кнопка для анализа
401
+ submit_button_2 = gr.Button("Провести экспресс-оценку", variant="primary", scale=2) # scale=2 делает ее в 2 раза шире
402
+
403
+ gr.Markdown("---")
404
+ output_report_2 = gr.Markdown(label="Результат оценки")
405
+
406
+ # --- Привязка функций к кнопкам (остается без изменений) ---
407
+ submit_button_1.click(
408
+ fn=generate_regional_briefing,
409
+ inputs=[region_input_1, year_input_1],
410
+ outputs=[output_report_1, output_plot_1, output_table_1]
411
+ )
412
+
413
+ # --- ��ЗМЕНЕНИЕ №3: Добавляем обработчик для новой кнопки ---
414
+ example_button.click(
415
+ fn=lambda: example_text, # Простая функция, которая просто возвращает текст примера
416
+ inputs=None, # У нее нет входных данных
417
+ outputs=project_input_2 # Результат (текст) отправляется в наше поле для ввода
418
+ )
419
+
420
+ submit_button_2.click(
421
+ fn=analyze_new_project,
422
+ inputs=[region_input_2, project_input_2],
423
+ outputs=[output_report_2]
424
+ )
425
+
426
+ demo.launch(share=True, debug=True)