сырой текст задания → плоская карточка: solution.py
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user