#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ solution.py Простой скрипт, который принимает одну строку с описанием задания, передаёт её модели OpenAI через LangChain и получает валидированный объект TaskCard (Pydantic). Затем выводит сериализованную форму и краткую сводку. """ import os import sys from typing import List from pydantic import BaseModel, Field from langchain_core.prompts import PromptTemplate from langchain_openai import ChatOpenAI from langchain_core.output_parsers import PydanticOutputParser # --------------------------------------------------------------------------- # # 1. Модель данных карточки задания # --------------------------------------------------------------------------- # class TaskCard(BaseModel): """ Карточка задачи, которую генерирует модель. """ title: str = Field( ..., description="Краткое название задачи (например, «Мини‑отчёт по LangChain»).", ) subject: str | None = Field( None, description="Тема или предмет, к которому относится задача.", ) deadline_hint: str | None = Field( None, description=( "Неформальное указание срока сдачи (например, «к пятнице»)." ), ) deliverable_type: str | None = Field( None, description="Тип сдаваемого материала (отчёт, код, презентация и т.п.).", ) grading_hints: List[str] | None = Field( None, description=( "Ключевые критерии оценки. Каждый элемент списка – отдельный пункт." ), ) # --------------------------------------------------------------------------- # # 2. Настройка LLM и парсера # --------------------------------------------------------------------------- # # Параметры модели можно менять через переменные окружения. OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini") TEMPERATURE = float(os.getenv("OPENAI_TEMPERATURE", "0")) llm = ChatOpenAI( model=OPENAI_MODEL, temperature=TEMPERATURE, ) parser = PydanticOutputParser(pydantic_object=TaskCard) # --------------------------------------------------------------------------- # # 3. Шаблон промпта # --------------------------------------------------------------------------- # prompt_template = PromptTemplate( template=""" Вы — помощник, который преобразует неформальное описание задания в структурированный формат. Пожалуйста, выведите только JSON‑объект с полями, которые описаны ниже. {format_instructions} Входное описание: "{input_text}" """, input_variables=["input_text"], partial_variables={"format_instructions": parser.get_format_instructions()}, ) # --------------------------------------------------------------------------- # # 4. Цепочка (prompt → LLM → парсер) # --------------------------------------------------------------------------- # chain = prompt_template | llm | parser # --------------------------------------------------------------------------- # # 5. Вспомогательная функция для вывода сводки # --------------------------------------------------------------------------- # def summarize(card: TaskCard) -> str: """ Формирует краткую человекочитаемую сводку из объекта TaskCard. """ parts = [f"**{card.title}**"] if card.subject: parts.append(f"(предмет: {card.subject})") if card.deadline_hint: parts.append(f"Срок сдачи: {card.deadline_hint}") if card.deliverable_type: parts.append(f"Тип сдаваемого материала: {card.deliverable_type}") if card.grading_hints: hints = ", ".join(card.grading_hints) parts.append(f"Критерии оценки: {hints}") return " | ".join(parts) # --------------------------------------------------------------------------- # # 6. Точка входа # --------------------------------------------------------------------------- # def main() -> None: if len(sys.argv) > 1: # Если передан аргумент, считаем его описанием задания input_text = " ".join(sys.argv[1:]) else: # Иначе читаем из stdin (первую строку) print("Введите описание задания:") input_text = sys.stdin.readline().strip() if not input_text: print("Ошибка: входной текст пуст.") sys.exit(1) try: card: TaskCard = chain.invoke({"input_text": input_text}) except Exception as exc: print(f"Не удалось получить структуру от модели: {exc}") sys.exit(1) # Вывод валидированного объекта print("\n=== Валидированный объект ===") print(card.model_dump(indent=2)) # Краткая сводка print("\n=== Сводка задачи ===") print(summarize(card)) if __name__ == "__main__": main()