File size: 37,985 Bytes
d60faab
 
 
 
 
 
 
 
 
 
 
 
76b49f2
d60faab
76b49f2
 
 
 
 
d60faab
76b49f2
 
 
 
 
 
 
 
 
d60faab
76b49f2
d60faab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0ff589
 
 
 
 
 
 
 
 
 
 
 
 
 
d60faab
 
 
 
 
 
 
 
 
 
c0ff589
d60faab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29c67bb
 
 
 
d60faab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0ff589
 
 
 
d60faab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0ff589
 
 
 
d60faab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29c67bb
 
 
 
 
d60faab
 
 
 
5230d4d
d60faab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6dc5a90
d60faab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a543854
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
import os
import requests
import json
import gradio as gr
import pandas as pd
import matplotlib.pyplot as plt
import pypdf
import warnings
from langchain_google_genai import ChatGoogleGenerativeAI

warnings.filterwarnings("ignore", category=UserWarning)

# --- 1. Настройка констант, API и LLM ---
print("--- Настройка API и LLM ---")

# Определяем константу здесь, чтобы она была доступна всегда
API_BASE_URL = "http://194.113.209.48:8000"
llm = None # Инициализируем llm как None на случай ошибки

try:
    # Ключ считывается из "секретов", которые вы задали в настройках Space
    GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY') 
    
    if GEMINI_API_KEY:
        llm = ChatGoogleGenerativeAI(model="gemini-1.5-pro-latest", google_api_key=GEMINI_API_KEY, temperature=0.1)
        print("✅ LLM настроена.")
    else:
        print("❌ ОШИБКА: Секрет 'GEMINI_API_KEY' не найден. Убедитесь, что он добавлен в настройках Space.")

except Exception as e:
    print(f"❌ Произошла ошибка при настройке LLM: {e}")


# --- 3. Загрузка данных и контекста ---
# 3.1. Загружаем заранее проанализированный портфель из CSV
print("--- Загрузка данных портфеля ---")
try:
    tagged_portfolio_df = pd.read_csv('sber_portfolio_analyzed5.csv')
    tagged_portfolio_df['region_name'] = tagged_portfolio_df['region_name'].str.strip()
    print(f"✅ Успешно загружен проанализированный портфель из {len(tagged_portfolio_df)} проектов.")
except FileNotFoundError:
    print("❌ Ошибка: Файл 'sber_portfolio_analyzed5.csv' не найден. Возможно, нужно сначала запустить ячейку для генерации этого файла.")
    tagged_portfolio_df = pd.DataFrame()

# 3.2. Извлекаем текст из PDF-отчета
print("--- Извлечение текста из PDF-отчета ---")
full_report_text = ""
try:
    # Убедитесь, что имя файла верное и он загружен
    with open('f356d44202ac9361579f509ebf965950.pdf', 'rb') as f:
        reader = pypdf.PdfReader(f)
        for page in reader.pages:
            full_report_text += page.extract_text() + "\n"
    print("✅ Текст из PDF-файла успешно извлечен.")
except Exception as e:
    print(f"❌ Ошибка при чтении PDF-файла: {e}")

# 3.3. Загружаем некредитные продукты
print("--- Извлечение текста из каталога продуктов ---")
sber_products_text = ""
try:
    # Убедитесь, что файл products.pdf загружен в ваш Space
    with open('products.pdf', 'rb') as f:
        reader = pypdf.PdfReader(f)
        for page in reader.pages:
            sber_products_text += page.extract_text() + "\n"
    print("✅ Текст из PDF-файла (Каталог продуктов) успешно извлечен.")
except Exception as e:
    print(f"❌ Ошибка при чтении PDF-файла (Каталог продуктов): {e}")

# 3.4. Загружаем справочники
print("--- Загрузка справочников ---")
try:
    regions_response = requests.get(f"{API_BASE_URL}/api/regions")
    regions_data = regions_response.json()
    regions_list = sorted([item['name'] for item in regions_data])
    print("✅ Справочник регионов загружен.")
except Exception as e:
    print(f"❌ Не удалось загрузить справочник регионов: {e}")
    regions_list = sorted(list(tagged_portfolio_df['region_name'].unique()))

# 3.5. Определяем константы (структура Наццелей) - ПОЛНАЯ ВЕРСИЯ
NATIONAL_GOALS_STRUCTURE = {
    "Сохранение населения, укрепление здоровья и повышение благополучия людей, поддержка семьи": [
        "2.а) повышение суммарного коэффициента рождаемости до 1,6 к 2030 году и до 1,8 к 2036 году",
        "2.б) увеличение ожидаемой продолжительности жизни до 78 лет к 2030 году и до 81 года к 2036 году",
        "2.в) обеспечение не ниже среднероссийских темпов повышения к 2030 году суммарного коэффициента рождаемости в отстающих субъектах РФ",
        "2.г) снижение к 2036 году дифференциации показателей ожидаемой продолжительности жизни не менее чем на 25%",
        "2.д) снижение к 2030 году суммарной продолжительности временной нетрудоспособности граждан",
        "2.е) повышение к 2030 году уровня удовлетворенности граждан условиями для занятий физкультурой и спортом",
        "2.ж) увеличение к 2030 году численности граждан, получающих услуги долговременного ухода, до 500 тыс. человек",
        "2.з) повышение к 2030 году уровня удовлетворенности участников СВО условиями для медицинской реабилитации и трудоустройства",
        "2.и) создание и запуск к 2030 году цифровой платформы по управлению здоровьем человека",
        "2.к) снижение уровня бедности ниже 7% к 2030 году и ниже 5% к 2036 году, в т.ч. среди многодетных семей",
        "2.л) снижение коэффициента Джини до 0,37 к 2030 году и до 0,33 к 2036 году",
        "2.м) рост МРОТ к 2030 году более чем в два раза, не менее 35 тыс. рублей в месяц",
        "2.н) утверждение в 2026 году новых систем оплаты труда работников бюджетной сферы"
    ],
    "Реализация потенциала каждого человека, развитие его талантов, воспитание патриотичной и социально ответственной личности": [
        "3.а) создание к 2030 году условий для воспитания гармонично развитой личности на основе традиционных ценностей",
        "3.б) увеличение к 2030 году численности иностранных студентов до 500 тыс. человек",
        "3.в) увеличение к 2030 году доли молодых людей, участвующих в проектах развития и воспитания, до 75%",
        "3.г) увеличение к 2030 году доли молодых людей, верящих в самореализацию в России, до 85%",
        "3.д) увеличение к 2030 году доли молодых людей в добровольческой деятельности до 45%",
        "3.е) обеспечение к 2030 году функционирования эффективной системы выявления талантов у 100% обучающихся",
        "3.ж) обеспечение продвижения традиционных ценностей в не менее чем 70% проектов в сфере культуры к 2030 году",
        "3.з) повышение к 2030 году удовлетворенности граждан работой организаций культуры",
        "3.и) формирование к 2030 году современной системы профразвития педагогических работников"
    ],
    "Комфортная и безопасная среда для жизни": [
        "4.а) улучшение качества среды для жизни в опорных населенных пунктах на 30% к 2030 году",
        "4.б) обеспечение граждан жильем общей площадью не менее 33 кв. метров на человека к 2030 году",
        "4.в) обновление к 2030 году жилищного фонда не менее чем на 20% по сравнению с 2019 годом",
        "4.г) устойчивое сокращение непригодного для проживания жилищного фонда",
        "4.д) повышение доступности жилья на первичном рынке",
        "4.е) благоустройство не менее чем 30 тыс. общественных территорий к 2030 году",
        "4.ж) реализация программы модернизации коммунальной инфраструктуры для 20 млн. человек к 2030 году",
        "4.з) строительство и реконструкция не менее чем 2 тыс. объектов питьевого водоснабжения к 2030 году",
        "4.и) рост энергоэффективности в ЖКХ и строительстве",
        "4.к) обновление парка общественного транспорта до 85% от норматива к 2030 году",
        "4.л) приведение в нормативное состояние 85% дорог агломераций и 60% региональных дорог к 2030 году",
        "4.м) снижение смертности в ДТП в 1.5 раза к 2030 году",
        "4.н) увеличение авиационной подвижности населения на 50% к 2030 году",
        "4.о) капитальный ремонт всех нуждающихся зданий школ и детсадов до конца 2030 года",
        "4.п) подключение к сетевому газу не менее 1,6 млн домовладений к 2030 году",
        "4.р) оснащение 900 центров кинопоказа в малых населенных пунктах к 2030 году"
    ],
    "Экологическое благополучие": [
        "5.а) формирование экономики замкнутого цикла: 100% сортировка ТКО, захоронение не более 50%, вовлечение 25% отходов в оборот к 2030 году",
        "5.б) снижение в два раза выбросов опасных загрязняющих веществ в городах с высоким уровнем загрязнения к 2036 году",
        "5.в) ликвидация до конца 2030 года не менее 50 опасных объектов накопленного вреда",
        "5.г) снижение к 2036 году в два раза объема неочищенных сточных вод",
        "5.д) сохранение лесов, биоразнообразия и создание условий для экологического туризма"
    ],
    "Устойчивая и динамичная экономика": [
        "6.а) темп роста ВВП выше среднемирового, 4-е место в мире по ВВП по ППС к 2030 году",
        "6.б) снижение доли импорта до 17% ВВП к 2030 году",
        "6.в) увеличение объема инвестиций в основной капитал на 60% к 2030 году (относительно 2020)",
        "6.г) рост доходов населения и пенсий не ниже уровня инфляции",
        "6.д) реальный рост дохода на работника МСП в 1,2 раза выше роста ВВП",
        "6.ж) вхождение в топ-25 стран мира по плотности роботизации к 2030 году",
        "6.н) увеличение доли туристской отрасли в ВВП до 5% к 2030 году",
        "6.о) прирост экспорта несырьевых неэнергетических товаров на две трети к 2030 году",
        "6.п) увеличение производства продукции АПК на 25% к 2030 году (относительно 2021)",
        "6.р) увеличение экспорта продукции АПК в 1.5 раза к 2030 году (относительно 2021)"
    ],
    "Технологическое лидерство": [
        "7.а) обеспечение технологической независимости (биоэкономика, БАС, ИИ, новые материалы и др.)",
        "7.б) увеличение индекса производства в обрабатывающей промышленности на 40% к 2030 году (относительно 2022)",
        "7.в) вхождение в топ-10 стран мира по объему научных исследований к 2030 году",
        "7.г) увеличение внутренних затрат на исследования до 2% ВВП к 2030 году",
        "7.д) увеличение доли отечественных высокотехнологичных товаров в 1.5 раза к 2030 году",
        "7.е) увеличение выручки малых технологических компаний в 7 раз к 2030 году"
    ],
    "Цифровая трансформация": [
        "8.а) достижение 'цифровой зрелости' госуправления и ключевых отраслей экономики к 2030 году",
        "8.б) формирование рынка данных",
        "8.в) доступ к высокоскоростному интернету для 97% домохозяйств к 2030 году",
        "8.г) рост инвестиций в отечественные ИТ-решения вдвое выше темпа роста ВВП",
        "8.д) переход 80% организаций на российское ПО к 2030 году"
    ]
}
print("✅ Словарь НАЦЦЕЛЕЙ успешно загружен.")

# --- 4. Определение функций приложения ---
print("--- Определение функций приложения ---")
# (Здесь идут полные определения функций generate_regional_briefing, _find_relevant_goals, analyze_new_project)
# --- ФИНАЛЬНАЯ ВЕРСИЯ С ТАБЛИЧНЫМ ПРЕДСТАВЛЕНИЕМ АНАЛИЗА ---

def generate_regional_briefing(region_name, year):
    print("---")
    print(f"НОВЫЙ ЗАПРОС [Стратегический обзор]:")
    print(f"Регион: {region_name}, Год: {year}")
    print("---")
    if not region_name or not year:
        yield "Пожалуйста, выберите регион и год.", None, None
        return

    if not 'full_report_text' in globals() or not full_report_text:
        yield "Ошибка: Текст отчета ESG-индекса не был загружен.", None, None
        return

    yield "<h3 style='margin-top: 20px;'>⏳ Готовлю финальный отчет, это может занять до 30 секунд...</h3>", None, None

    try:
        region_id = next((item['id'] for item in regions_data if item['name'] == region_name), None)
        params = {"year": int(year)}
        response = requests.get(f"{API_BASE_URL}/api/region-performance/{region_id}/all", params=params)
        response.raise_for_status()
        urfu_data_raw = response.json()
        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}
    except Exception as e:
        yield f"Не удалось получить данные от API УрФУ. Ошибка: {e}", None, None
        return

    region_portfolio = tagged_portfolio_df[tagged_portfolio_df['region_name'] == region_name]
    
    portfolio_summary = "В данном регионе у Сбера отсутствуют проекты из анализируемого портфеля."
    fig = None

    if not region_portfolio.empty:
        total_investment = region_portfolio['amount_bln_rub'].sum()
        project_count = len(region_portfolio)
        SUMMARIZATION_THRESHOLD = 5

        if 'mapped_goal' in region_portfolio.columns and not region_portfolio['mapped_goal'].isnull().all():
            if project_count > SUMMARIZATION_THRESHOLD:
                summary_parts = []
                goal_groups = region_portfolio.groupby('mapped_goal')['amount_bln_rub'].sum().sort_values(ascending=False).reset_index()

                for _, row in goal_groups.iterrows():
                    goal_name = row['mapped_goal']
                    goal_sum = row['amount_bln_rub']
                    project_examples = region_portfolio[region_portfolio['mapped_goal'] == goal_name]['project_goal'].head(2).tolist()
                    examples_text = ", ".join(project_examples)
                    # ИЗМЕНЕНИЕ: Формируем HTML-элемент списка <li> и используем <strong> для жирности
                    summary_parts.append(
                        f"<li><strong>{goal_name}</strong> ({goal_sum:.1f} млрд руб.), ключевые проекты: {examples_text}</li>"
                    )
                
                # ИЗМЕНЕНИЕ: Собираем полный HTML-список <ul>...</ul>
                summary_text = "<ul>" + "".join(summary_parts) + "</ul>"
                portfolio_summary = (
                    f"Портфель Сбера в регионе составляет {total_investment:.1f} млрд руб. и включает проекты, распределенные по следующим национальным целям:{summary_text}"
                )
            else:
                projects_list = [
                    f"'{row['project_goal']}' ({row['amount_bln_rub']:.1f} млрд руб.), направленный на достижение цели \"{row.get('mapped_goal', 'не определена')}\""
                    for _, row in region_portfolio.iterrows()
                ]
                projects_text = " и ".join(projects_list)
                portfolio_summary = (
                    f"Текущий портфель Сбера в регионе составляет {total_investment:.1f} млрд руб. "
                    f"и включает следующие ключевые проекты: {projects_text}."
                )
        else:
            projects_list = [
                f"'{row['project_goal']}' ({row['amount_bln_rub']:.1f} млрд руб.)"
                for _, row in region_portfolio.iterrows()
            ]
            projects_text = ", ".join(projects_list)
            portfolio_summary = (
                f"Текущий портфель Сбера в регионе составляет {total_investment:.1f} млрд руб. и включает следующие проекты: {projects_text}."
            )

        if 'mapped_goal' in region_portfolio.columns and not region_portfolio['mapped_goal'].isnull().all():
            goal_distribution = region_portfolio.groupby('mapped_goal')['amount_bln_rub'].sum()
            plot_data = goal_distribution.reset_index()
            if plot_data is not None and not plot_data.empty:
                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)
                plt.xticks(rotation=45, ha="right", fontsize=9); plt.title(f"Распределение портфеля Сбера по Наццелям\nв регионе: {region_name}", fontsize=12)
                plt.ylabel("Сумма, млрд руб.", fontsize=10); plt.grid(axis='y', linestyle='--', alpha=0.7); plt.tight_layout()
    
    prompt = f"""
    Твоя роль: Ведущий аналитик-стратег ESG-дирекции Сбера.
    Твоя задача: Подготовить исчерпывающий и СТРУКТУРИРОВАННЫЙ аналитический отчет по региону, синтезируя информацию из предоставленных источников.
    ### ИСТОЧНИК 1: Статистические показатели по региону (от УрФУ)
    Регион анализа: {region_name}
    {json.dumps(urfu_data_simplified, ensure_ascii=False, indent=2)}
    ### ИСТОЧНИК 2: Полный текст отчета "ESG-индекс городов и регионов" (Сбер, ВЭБ.РФ)
    ```text
    {full_report_text}
    ```
    ### ИСТОЧНИК 3: Данные по проектам в регионе
    {portfolio_summary}

    ### ИСТОЧНИК 4: Каталог некредитных продуктов экосистемы Сбера
    ```text
    {sber_products_text}
    ```
    ### ЗАДАЧА И СТРОГИЕ ПРАВИЛА:
    1.  Подготовь отчет в формате Markdown.
    2.  Сфокусируй детальный анализ ТОЛЬКО на двух Национальных целях: "Сохранение населения, укрепление здоровья и повышение благополучия людей, поддержка семьи" и "Комфортная и безопасная среда для жизни".
    3.  Относись ко всем данным как к реальным, не добавляй дисклеймеров.
    4.  Для раздела "Детальный анализ" **сгенерируй Markdown-таблицы**, как показано в шаблоне.
    ---
    ### Аналитический отчет: {region_name}, {year} год
    **1. Обзор проектов в регионе**
    * На основе ИСТОЧНИКА 3, опиши состав и объем проектов. Начинай с новой строки каждую новую Наццель и по ней проекты.
    * **Задача для следующей строки:** На основе ИСТОЧНИКА 2, найди конкретные факты о регионе `{region_name}` (место в рейтинге, баллы, и т.д.).
    * **Требование к форматированию:** Начни строку с "ESG-индекс городов и регионов Сбер - ВЭБ.РФ:". Сразу после этого, обычным черным текстом, продолжи своим аналитическим выводом.
    **2. Детальный анализ по приоритетным Национальным целям**
    * Для каждой из двух приоритетных Наццелей, создай подзаголовок и Markdown-таблицу по следующему образцу. Заполни 2-3 строки для каждой таблицы наиболее показательными данными.
    **Национальная цель: "Сохранение населения, укрепление здоровья и повышение благополучия людей, поддержка семьи"**
    | Показатель (данные УрФУ) | Значение в регионе | Влияние проектов Сбера |
    | :--- | :--- | :--- |
    | *[название показателя из ИСТОЧНИКА 1]* | *[значение из ИСТОЧНИКА 1]* | *[твой анализ ИСТОЧНИКА 3]* |
    | *[название второго показателя]* | *[его значение]* | *[твой анализ]* |
    **Национальная цель: "Комфортная и безопасная среда для жизни"**
    | Показатель (данные УрФУ) | Значение в регионе | Влияние проектов Сбера |
    | :--- | :--- | :--- |
    | *[название показателя из ИСТОЧНИКА 1]* | *[значение из ИСТОЧНИКА 1]* | *[твой анализ ИСТОЧНИКА 3]* |
    | *[название второго показателя]* | *[его значение]* | *[твой анализ]* |
    **3. Стратегические рекомендации**
    * **Шаг 1:** На основе табличного анализа, сформулируй 2-3 ключевых вывода и предложи конкретные **типы проектов** для инвестиций.
    * **Шаг 2:** Внимательно изучи **ИСТОЧНИК 4 (Каталог некредитных продуктов)**.
    * **Шаг 3:** Под твои рекомендации по типам проектов подбери 2-3 **наиболее релевантных продукта** из каталога.
    * **Шаг 4:** Оформи рекомендации в виде списка. Сначала общая рекомендация, а под ней — подпункт "Рекомендуемые продукты Сбера:" с названиями продуктов.
    """

    final_report = llm.invoke(prompt).content
    yield final_report, fig, region_portfolio.drop(columns=['project_goal'], errors='ignore')

def _find_relevant_goals(project_description: str) -> list:
    top_level_goals = list(NATIONAL_GOALS_STRUCTURE.keys())
    prompt = f"""
    Определи 1-3 наиболее релевантных национальных цели из списка для проекта. Верни ТОЛЬКО JSON-массив строк.
    СПИСОК НАЦЦЕЛЕЙ: {json.dumps(top_level_goals, ensure_ascii=False)}
    ОПИСАНИЕ ПРОЕКТА: "{project_description}"
    Твой JSON-ответ:
    """
    try:
        response = llm.invoke(prompt)
        return json.loads(response.content.strip().replace("```json", "").replace("```", ""))
    except Exception:
        return top_level_goals


def analyze_new_project(region_name, project_description):
    print("---")
    print(f"НОВЫЙ ЗАПРОС [Экспресс-оценка]:")
    print(f"Регион: {region_name}")
    print(f"Описание проекта: {project_description}")
    print("---")
    if not all([region_name, project_description]):
        yield "Пожалуйста, выберите регион и опишите проект."
        return

    yield "<h3 style='margin-top: 20px;'>⏳ Этап 1/2: Определяю релевантные Наццели...</h3>"
    relevant_goals_names = _find_relevant_goals(project_description)
    relevant_goals_structure = {goal: NATIONAL_GOALS_STRUCTURE.get(goal, []) for goal in relevant_goals_names}

    yield "<h3 style='margin-top: 20px;'>⏳ Этап 2/2: Готовлю детальный анализ, это может занять до 30 секунд...</h3>"

    try:
        region_id = next((item['id'] for item in regions_data if item['name'] == region_name), None)
        params = {"year": 2024} # Можно использовать актуальный год
        response = requests.get(f"{API_BASE_URL}/api/region-performance/{region_id}/all", params=params)
        response.raise_for_status()
        urfu_data_raw = response.json()
        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}
    except Exception as e:
        yield f"Не удалось получить данные от API УрФУ. Ошибка: {e}"
        return

    goals_structure_str = json.dumps(relevant_goals_structure, ensure_ascii=False, indent=2)

    # --- НАЧАЛО НОВОГО, РАСШИРЕННОГО ПРОМПТА ---
    prompt = f"""
    Твоя роль: Ведущий аналитик ESG-дирекции Сбера, обладающий глубокими знаниями в области национальных целей развития РФ.
    Твоя задача: Подготовить ДЕТАЛЬНЫЙ и СТРУКТУРИРОВАННЫЙ аналитический отчет по новому инвестиционному проекту. Отчет должен быть выполнен в формате Markdown и содержать глубокий анализ, а не поверхностное описание.
    ### ВХОДНЫЕ ДАННЫЕ:
    1.  **Регион реализации:** {region_name}
    2.  **Описание проекта:** "{project_description}"
    3.  **Статистический контекст по региону (данные УрФУ):** {json.dumps(urfu_data_simplified, ensure_ascii=False, indent=2)}
    4.  **Структура релевантных Национальных целей и их задач:** {goals_structure_str}
    ### СТРОГИЕ ТРЕБОВАНИЯ К СТРУКТУРЕ И СОДЕРЖАНИЮ ОТЧЕТА:
    **1. Краткое резюме проекта**
    * Опиши суть проекта, его масштаб и основные цели.
    **2. Анализ соответствия Национальным целям**
    * Для КАЖДОЙ релевантной наццели из предоставленного списка:
        * **Обоснуй, почему проект соответствует данной цели.** Четко свяжи деятельность по проекту с конкретными задачами (подпунктами) этой наццели.
        * **Используй данные из статистического контекста (ВХОДНЫЕ ДАННЫЕ №3)**, чтобы показать АКТУАЛЬНОСТЬ проекта для региона. Например, если проект влияет на здравоохранение, приведи текущие показатели по ожидаемой продолжительности жизни или заболеваемости в регионе, чтобы подчеркнуть важность инвестиций.
    **3. Оценка по ESG-критериям**
    * **E (Environmental / Экология):** Оцени потенциальное положительное и отрицательное воздействие проекта на окружающую среду. Какие экологические риски и возможности он несет? (например, снижение выбросов, образование отходов, использование "зеленых" технологий).
    * **S (Social / Социальная сфера):** Проанализируй социальный эффект. Создание рабочих мест (сколько, каких?), влияние на качество жизни, доступность услуг, поддержка местных сообществ.
    * **G (Governance / Управление):** Опиши потенциальные управленческие аспекты. Необходимость взаимодействия с региональными властями, прозрачность реализации, работа с заинтересованными сторонами.
    **4. Предварительные риски и рекомендации**
    * На основе всего анализа, выдели 2-3 ключевых риска (технологических, социальных, регуляторных), на которые стоит обратить внимание.
    * Дай 1-2 стратегические рекомендации по усилению положительного эффекта от проекта.
    **5. Итоговое заключение**
    * Сделай общий вывод о стратегической привлекательности проекта для банка с точки зрения вклада в устойчивое развитие и национальные приоритеты.
    ---
    **Начинай твой отчет.**
    """
    # --- КОНЕЦ НОВОГО ПРОМПТА ---

    analysis_report = llm.invoke(prompt).content
    yield analysis_report


# --- 5. Запуск веб-интерфейса Gradio ---
print("🚀 Запускаем Gradio-приложение...")
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:
    gr.Markdown(
        """<div style="text-align: center;"><img src="https://www.sberbank.com/common/img/uploaded/logo/logo_sber_main_2020_ru.svg" width="200">
        <h1>Интерактивный дашборд "Горизонт PRO"</h1><p>Анализ вклада в достижение Национальных целей РФ 2030/2036</p></div>"""
    )
    with gr.Tabs():
        with gr.TabItem("📈 Стратегический обзор региона"):
            with gr.Row():
                region_input_1 = gr.Dropdown(regions_list, label="Выберите регион")
                year_input_1 = gr.Dropdown([2025, 2024, 2023, 2022], label="Выберите год", value=2024)
            submit_button_1 = gr.Button("Сформировать стратегическую справку", variant="primary")
            gr.Markdown("---")
            output_report_1 = gr.Markdown(label="Аналитическая справка")

            # Элементы создаются, но не отображаются в интерфейсе
            # Это необходимо, чтобы функция click могла в них вернуть значения без ошибки.
            output_plot_1 = gr.Plot(visible=False)
            output_table_1 = gr.DataFrame(label="Проекты в портфеле", visible=False)


        with gr.TabItem("🔎 Экспресс-оценка нового проекта"):
            # --- ИЗМЕНЕНИЕ №1: Выносим текст примера в отдельную переменную ---
            example_text = "Мусоросортировочный завод на 150 000 тонн стоимостью 3 млрд руб"

            gr.Markdown("Введите описание нового инвестиционного проекта для анализа его соответствия Национальным целям и потребностям региона.")
            region_input_2 = gr.Dropdown(regions_list, label="Выберите регион реализации проекта")
            project_input_2 = gr.Textbox(lines=4, label="Опишите проект", placeholder=f"Пример: {example_text}")

            # --- ИЗМЕНЕНИЕ №2: Добавляем две кнопки в одну строку ---
            with gr.Row():
                # Кнопка для вставки примера
                example_button = gr.Button("✍️ Вставить пример", variant="secondary")
                # Основная кнопка для анализа
                submit_button_2 = gr.Button("Провести экспресс-оценку", variant="primary", scale=2) # scale=2 делает ее в 2 раза шире

            gr.Markdown("---")
            output_report_2 = gr.Markdown(label="Результат оценки")

    # --- Привязка функций к кнопкам (остается без изменений) ---
    submit_button_1.click(
        fn=generate_regional_briefing,
        inputs=[region_input_1, year_input_1],
        outputs=[output_report_1, output_plot_1, output_table_1]
    )

    # --- ИЗМЕНЕНИЕ №3: Добавляем обработчик для новой кнопки ---
    example_button.click(
        fn=lambda: example_text, # Простая функция, которая просто возвращает текст примера
        inputs=None,              # У нее нет входных данных
        outputs=project_input_2   # Результат (текст) отправляется в наше поле для ввода
    )

    submit_button_2.click(
        fn=analyze_new_project,
        inputs=[region_input_2, project_input_2],
        outputs=[output_report_2]
    )

demo.launch(share=True, debug=True)