From 8406b4f2e7395e75684bccb84c1fbe58e8726760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B4=D0=B5=D0=BB=D0=B8=D0=BD=D0=B0=20=D0=A1=D0=B0?= =?UTF-8?q?=D1=82=D1=82=D0=B0=D1=80=D0=BE=D0=B2=D0=B0?= Date: Thu, 28 May 2026 11:12:20 +0000 Subject: [PATCH] add parser.py --- parser.py | 177 +++++++++++++++++++++++++++--------------------------- 1 file changed, 90 insertions(+), 87 deletions(-) diff --git a/parser.py b/parser.py index 6797ce7..ddad37a 100644 --- a/parser.py +++ b/parser.py @@ -1,108 +1,111 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + """ -Raw text → flat card parser. +Пример преобразования неформального описания задания в структурированный объект. -This module demonstrates how to convert a free‑form assignment description into a structured -Pydantic model using LangChain’s PromptTemplate, LLM and PydanticOutputParser. - -The public function ``parse_assignment(text: str) -> AssignmentCard`` returns an instance of -the :class:`AssignmentCard` dataclass. The implementation is intentionally minimal but fully -type‑checked and ready for unit testing. +Используем: +* LangChain (core + OpenAI) +* Pydantic для типизации и проверки результата """ -from __future__ import annotations +import os +from pathlib import Path -from dataclasses import dataclass -from typing import List, Dict - -# LangChain imports – the core library provides PromptTemplate and LLM wrappers from langchain_core.prompts import PromptTemplate from langchain_openai import ChatOpenAI -from langchain.output_parsers import PydanticOutputParser +from langchain_core.output_parsers import PydanticOutputParser from pydantic import BaseModel, Field -# --------------------------------------------------------------------------- -# 1. Define the output schema with Pydantic -# --------------------------------------------------------------------------- + +# ------------------------------------------------------------------ +# 1. Модель карточки задания (Pydantic) +# ------------------------------------------------------------------ class AssignmentCard(BaseModel): - """Structured representation of an assignment description. + title: str = Field(..., description="Краткое название задачи") + subject: str = Field( + ..., description="Предмет/тема, к которой относится задание" + ) + deadline_hint: str | None = Field( + None, + description="Указание дедлайна в свободной форме (например, «к пятнице»)", + ) + deliverable_type: str = Field( + ..., + description=( + "Тип сдачи: отчёт, код, презентация и т.п. " + "(если однотипное – перечислите без пунктов)" + ), + ) + grading_hints: list[str] | None = Field( + None, + description="Ключевые критерии оценки (список строк)", + ) - Attributes - ---------- - title : str - Short title of the task. - subject : str - Subject or topic covered by the assignment. - deadline_hint : str | None - Human‑readable hint about the due date (e.g. "by Friday"). - deliverable_type : str - What should be submitted – e.g. "report", "code". - grading_hints : List[str] - Optional list of hints that influence grading. - """ - title: str = Field(..., description="Short title of the task") - subject: str = Field(..., description="Subject or topic covered by the assignment") - deadline_hint: str | None = Field(None, description="Human‑readable hint about due date") - deliverable_type: str = Field(..., description="What should be submitted – e.g. report, code") - grading_hints: List[str] = Field(default_factory=list, description="Hints that influence grading") - -# --------------------------------------------------------------------------- -# 2. Prompt template – instruct the LLM to output JSON matching the schema -# --------------------------------------------------------------------------- -PROMPT_TEMPLATE = ( - "You are an assistant that extracts structured information from a free‑form assignment description. - Return a JSON object with the following fields exactly as defined in the AssignmentCard model: - {{schema}} - The input text is: "{{text}}" - """) - -# --------------------------------------------------------------------------- -# 3. Parser that validates the LLM output against the Pydantic schema -# --------------------------------------------------------------------------- +# ------------------------------------------------------------------ +# 2. Парсер и промпт +# ------------------------------------------------------------------ parser = PydanticOutputParser(pydantic_object=AssignmentCard) -# --------------------------------------------------------------------------- -# 4. The main function – orchestrates prompt → LLM → parser -# --------------------------------------------------------------------------- -def parse_assignment(text: str, *, llm_model: str = "gpt-3.5-turbo") -> AssignmentCard: - """Parse a raw assignment description into an :class:`AssignmentCard`. +prompt_template = """ +Пожалуйста, преобразуйте следующее описание задания в JSON‑объект, +соответствующий схеме: - Parameters - ---------- - text : str - Free‑form assignment description. - llm_model : str, optional - Name of the OpenAI model to use. Defaults to ``gpt-3.5-turbo``. +{format_instructions} - Returns - ------- - AssignmentCard - Validated dataclass instance. - """ - # Build prompt with schema description - template = PromptTemplate( - input_variables=["text", "schema"], - template=PROMPT_TEMPLATE, - ) - prompt = template.format(text=text, schema=parser.get_format_instructions()) +Текст задания: +"{input_text}" +""" - # Call the LLM – we use ChatOpenAI from langchain_openai for simplicity - llm = ChatOpenAI(model_name=llm_model, temperature=0) - raw_output = llm.invoke(prompt).content +prompt = PromptTemplate( + template=prompt_template, + input_variables=["input_text"], + partial_variables={"format_instructions": parser.get_format_instructions()}, +) - # Parse and validate - return parser.parse(raw_output) +# ------------------------------------------------------------------ +# 3. Модель LLM +# ------------------------------------------------------------------ +llm = ChatOpenAI(temperature=0, model="gpt-4o-mini") # можно поменять модель -# --------------------------------------------------------------------------- -# 5. Demo – run when executed as a script -# --------------------------------------------------------------------------- +# Создаём цепочку: Prompt → LLM → Parser +chain = prompt | llm | parser + + +# ------------------------------------------------------------------ +# 4. Функция «обработки» одной строки +# ------------------------------------------------------------------ +def parse_assignment(text: str) -> AssignmentCard: + """Возвращает валидированную модель из текста.""" + return chain.invoke({"input_text": text}) + + +# ------------------------------------------------------------------ +# 5. Тестовый пример (можно заменить на любой другой) +# ------------------------------------------------------------------ if __name__ == "__main__": - import os - if not os.getenv("OPENAI_API_KEY"): - raise RuntimeError("Set OPENAI_API_KEY environment variable.") - - sample = ( - "Сдайте к пятнице мини‑отчёт по LangChain. В отчёте должно быть описание модели, пример кода и выводы." + example = ( + "Сдайте к пятнице мини‑отчёт по LangChain: " + "2 страницы, упор на агентов. Оценка: за полноту и за пример кода." ) - card = parse_assignment(sample) - print("Parsed assignment:", card.json(indent=2)) + card = parse_assignment(example) + + # Выводим модель в виде JSON + print("\n=== Валидация ===") + print(card.model_dump(indent=4)) + + # Краткая человекочитаемая сводка + print("\n=== Сводка ===") + print(f"Тема: {card.subject}") + print(f"Название: {card.title}") + if card.deadline_hint: + print(f"Дедлайн: {card.deadline_hint}") + print(f"Сдача: {card.deliverable_type}") + if card.grading_hints: + print("Критерии оценки:") + for h in card.grading_hints: + print(f" • {h}") + + +# ────────────────────── End of file ─────────────────────