From 69b5a28265cb41da88051c245a9338ed6544bf3c Mon Sep 17 00:00:00 2001 From: lonpatovaadelina Date: Fri, 29 May 2026 06:54:27 +0000 Subject: [PATCH] =?UTF-8?q?=D0=AD=D0=BA=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD:=20?= =?UTF-8?q?=D0=A1=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=B2=D1=8B=D0=B2?= =?UTF-8?q?=D0=BE=D0=B4=20(Pydantic):=20solution.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- solution.py | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 solution.py diff --git a/solution.py b/solution.py new file mode 100644 index 0000000..75534de --- /dev/null +++ b/solution.py @@ -0,0 +1,127 @@ +import os +import argparse +from datetime import datetime +from typing import List, Union + +from langchain_core.prompts import PromptTemplate +from langchain_core.output_parsers import PydanticOutputParser +from langchain_core.runnables import Runnable +from langchain_openai import ChatOpenAI +from pydantic import BaseModel, Field + +# ------------------------------------------------------------------ +# 1. Pydantic модели +# ------------------------------------------------------------------ +class PersonInfo(BaseModel): + name: str = Field(..., description="Имя человека") + age: int | None = Field(None, description="Возраст (необязательно)") + profession: str = Field(..., description="Профессия") + skills: List[str] = Field(..., description="Список навыков") + +class MeetingNotes(BaseModel): + date: datetime = Field(..., description="Дата встречи в формате YYYY-MM-DD") + participants: List[str] = Field(..., description="Список участников") + topics: List[str] = Field(..., description="Темы обсуждения") + decisions: List[str] = Field(..., description="Принятые решения") + next_steps: List[str] = Field(..., description="Следующие шаги") + +# ------------------------------------------------------------------ +# 2. Шаблоны и парсеры +# ------------------------------------------------------------------ +person_prompt = PromptTemplate( + input_variables=["text"], + template=( + "Найди в тексте информацию о человеке и выведи её в формате JSON, " + "соответствующем схеме PersonInfo.\n" + "Текст: {text}\n" + "Формат: {format_instructions}" + ), +) + +meeting_prompt = PromptTemplate( + input_variables=["text"], + template=( + "Найди в тексте информацию о встрече и выведи её в формате JSON, " + "соответствующем схеме MeetingNotes.\n" + "Текст: {text}\n" + "Формат: {format_instructions}" + ), +) + +person_parser = PydanticOutputParser(pydantic_object=PersonInfo) +meeting_parser = PydanticOutputParser(pydantic_object=MeetingNotes) + +person_chain = ( + person_prompt | ChatOpenAI(temperature=0) | person_parser +) +meeting_chain = ( + meeting_prompt | ChatOpenAI(temperature=0) | meeting_parser +) + +# ------------------------------------------------------------------ +# 3. Выбор схемы +# ------------------------------------------------------------------ +def choose_chain(text: str) -> Runnable: + """Определяем, какой тип данных в тексте.""" + lowered = text.lower() + # простая эвристика: наличие ключевых слов + if any(word in lowered for word in ("встреча", "meeting", "дата", "participants", "topics")): + return meeting_chain + return person_chain + +# ------------------------------------------------------------------ +# 4. CLI +# ------------------------------------------------------------------ +def main(): + parser = argparse.ArgumentParser(description="Structured output extractor") + parser.add_argument( + "--text", + type=str, + help="Текст для обработки. Если не задан, используется пример.", + ) + args = parser.parse_args() + + if args.text: + input_text = args.text + else: + # пример для PersonInfo + input_text = ( + "Анна, 28 лет, Python-разработчик. Навыки: FastAPI, Docker." + ) + # пример для MeetingNotes + # input_text = ( + # "Дата: 2024-05-01. Участники: Анна, Боб. Темы: проект X, бюджет. " + # "Решения: утвердить бюджет. Next steps: подготовить презентацию." + # ) + + chain = choose_chain(input_text) + result = chain.invoke({"text": input_text}) + + # result уже валидированный объект Pydantic + print("\nВыполнено. Валидированный объект:") + print(result.model_dump(indent=2)) + + # Краткая сводка + if isinstance(result, PersonInfo): + summary = ( + f"Человек: {result.name}, " + f"возраст: {result.age if result.age is not None else 'не указан'}, " + f"профессия: {result.profession}, " + f"навыки: {', '.join(result.skills)}" + ) + else: + summary = ( + f"Встреча: {result.date.date()}, " + f"участники: {', '.join(result.participants)}, " + f"темы: {', '.join(result.topics)}, " + f"решения: {', '.join(result.decisions)}, " + f"следующие шаги: {', '.join(result.next_steps)}" + ) + print("\nСводка:") + print(summary) + +if __name__ == "__main__": + # Для работы с OpenAI требуется переменная окружения OPENAI_API_KEY + if "OPENAI_API_KEY" not in os.environ: + raise RuntimeError("Необходимо задать переменную окружения OPENAI_API_KEY") + main() \ No newline at end of file