From f5a43e87dab20f61f0e5ce5ad53c95fd1350aa44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=9A=D1=83=D1=82?= =?UTF-8?q?=D0=BB=D0=B0=D1=85=D0=BC=D0=B5=D1=82=D0=BE=D0=B2?= Date: Wed, 27 May 2026 13:32:34 +0000 Subject: [PATCH] add main.py --- main.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 main.py diff --git a/main.py b/main.py new file mode 100644 index 0000000..ec2f237 --- /dev/null +++ b/main.py @@ -0,0 +1,111 @@ +""" +Main entry point for the "сырой текст задания → плоская карточка" task. + +The script demonstrates how to convert a free‑form description of an assignment into a structured data object using LangChain and Pydantic. + +Usage examples are provided in the ``__main__`` section – three different raw texts are parsed and printed. +""" + +from __future__ import annotations + +import os +from typing import List + +from langchain_openai import ChatOpenAI +from langchain_core.prompts import PromptTemplate +from langchain_core.output_parsers import PydanticOutputParser +from pydantic import BaseModel, Field + +# --------------------------------------------------------------------------- +# 1. Define the data model that represents a task card. +# --------------------------------------------------------------------------- +class TaskCard(BaseModel): + """Structured representation of an assignment description. + + The fields are intentionally generic – they capture the most common pieces of information + that appear in the course tasks: + + * ``title`` – short name of the task. + * ``subject`` – subject or topic area. + * ``deadline_hint`` – free‑form hint about when the task should be finished. + * ``deliverable_type`` – what is expected to be submitted (report, code, presentation…). + * ``grading_hints`` – list of items that influence grading. + """ + + title: str = Field(..., description="Short name of the task") + subject: str | None = Field(None, description="Subject or topic area") + deadline_hint: str | None = Field( + None, + description="Free‑form hint about when the task should be finished", + ) + deliverable_type: str | None = Field( + None, + description="What is expected to be submitted (report, code, presentation…)", + ) + grading_hints: List[str] = Field( + default_factory=list, + description="List of items that influence grading", + ) + +# --------------------------------------------------------------------------- +# 2. Build the prompt and parser. +# --------------------------------------------------------------------------- +parser = PydanticOutputParser(pydantic_object=TaskCard) + +prompt_template = PromptTemplate( + template=( + "You are an assistant that extracts structured information from a free‑form task description." + " Return only the data in JSON format that matches the following schema:\n{format_instructions}\n" + "Input: {text}" + ), + input_variables=["text"], + partial_variables={"format_instructions": parser.get_format_instructions()}, +) + +# --------------------------------------------------------------------------- +# 3. Create the LLM instance. +# --------------------------------------------------------------------------- +llm = ChatOpenAI( + model="openai/gpt-oss-20b:free", + base_url="https://platform.brojs.ru/jrnl-bh/api/inference/v1", + api_key=os.getenv("JOURNAL_MCP_PAT"), + temperature=0.0, +) + +# --------------------------------------------------------------------------- +# 4. Helper that runs the chain and returns a TaskCard. +# --------------------------------------------------------------------------- +async def parse_task(text: str) -> TaskCard: + """Parse *text* into a :class:`TaskCard` using LangChain. + + The function is asynchronous because ``ChatOpenAI`` uses an async API. It can be called from + synchronous code via ``asyncio.run``. + """ + + chain = prompt_template | llm | parser + result = await chain.ainvoke({"text": text}) + return result + +# --------------------------------------------------------------------------- +# 5. Demo – three example texts. +# --------------------------------------------------------------------------- +if __name__ == "__main__": + import asyncio + + examples = [ + "Сдайте к пятнице мини‑отчёт по LangChain: 2 страницы, упор на агентов. Оценка: за полноту и за пример кода.", + "На следующей неделе подготовьте презентацию о Qdrant. Должно быть 10 слайдов, включать примеры кода. Оценка по содержанию и дизайну.", + "Разработайте скрипт на Python, который генерирует случайный пароль длиной 12 символов. Сдача – код в репозитории. Оценка: корректность и безопасность.", + ] + + async def demo(): + for i, txt in enumerate(examples, start=1): + card = await parse_task(txt) + print(f"\nExample {i}:") + print("Raw text:") + print(txt) + print("\nParsed card: ") + # Pretty‑print the model using ``model_dump`` – it returns a dict. + print(card.model_dump(indent=2, sort_keys=False)) + + asyncio.run(demo())