mirror of https://github.com/hwchase17/langchain
Harrison/datetime parser (#4693)
Co-authored-by: Jacob Valdez <jacobfv@msn.com> Co-authored-by: Jacob Valdez <jacob.valdez@limboid.ai> Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>pull/5413/head
parent
1837caa70d
commit
2da8c48be1
@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "07311335",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Datetime\n",
|
||||||
|
"\n",
|
||||||
|
"This OutputParser shows out to parse LLM output into datetime format."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"id": "77e49a3d",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from langchain.prompts import PromptTemplate\n",
|
||||||
|
"from langchain.output_parsers import DatetimeOutputParser\n",
|
||||||
|
"from langchain.chains import LLMChain\n",
|
||||||
|
"from langchain.llms import OpenAI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"id": "ace93488",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"output_parser = DatetimeOutputParser()\n",
|
||||||
|
"template = \"\"\"Answer the users question:\n",
|
||||||
|
"\n",
|
||||||
|
"{question}\n",
|
||||||
|
"\n",
|
||||||
|
"{format_instructions}\"\"\"\n",
|
||||||
|
"prompt = PromptTemplate.from_template(template, partial_variables={\"format_instructions\": output_parser.get_format_instructions()})"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"id": "9240a3ae",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"chain = LLMChain(prompt=prompt, llm=OpenAI())"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
|
"id": "ad62eacc",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"output = chain.run(\"around when was bitcoin founded?\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 6,
|
||||||
|
"id": "96657765",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"'\\n\\n2008-01-03T18:15:05.000000Z'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 6,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"output"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 5,
|
||||||
|
"id": "bf714e52",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"datetime.datetime(2008, 1, 3, 18, 15, 5)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 5,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"output_parser.parse(output)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "a56112b1",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3 (ipykernel)",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import random
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from langchain.schema import BaseOutputParser, OutputParserException
|
||||||
|
from langchain.utils import comma_list
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_random_datetime_strings(
|
||||||
|
pattern: str,
|
||||||
|
n: int = 3,
|
||||||
|
start_date: datetime = datetime(1, 1, 1),
|
||||||
|
end_date: datetime = datetime.now() + timedelta(days=3650),
|
||||||
|
) -> List[str]:
|
||||||
|
"""
|
||||||
|
Generates n random datetime strings conforming to the
|
||||||
|
given pattern within the specified date range.
|
||||||
|
Pattern should be a string containing the desired format codes.
|
||||||
|
start_date and end_date should be datetime objects representing
|
||||||
|
the start and end of the date range.
|
||||||
|
"""
|
||||||
|
examples = []
|
||||||
|
delta = end_date - start_date
|
||||||
|
for i in range(n):
|
||||||
|
random_delta = random.uniform(0, delta.total_seconds())
|
||||||
|
dt = start_date + timedelta(seconds=random_delta)
|
||||||
|
date_string = dt.strftime(pattern)
|
||||||
|
examples.append(date_string)
|
||||||
|
return examples
|
||||||
|
|
||||||
|
|
||||||
|
class DatetimeOutputParser(BaseOutputParser[datetime]):
|
||||||
|
format: str = "%Y-%m-%dT%H:%M:%S.%fZ"
|
||||||
|
|
||||||
|
def get_format_instructions(self) -> str:
|
||||||
|
examples = comma_list(_generate_random_datetime_strings(self.format))
|
||||||
|
return f"""Write a datetime string that matches the
|
||||||
|
following pattern: "{self.format}". Examples: {examples}"""
|
||||||
|
|
||||||
|
def parse(self, response: str) -> datetime:
|
||||||
|
try:
|
||||||
|
return datetime.strptime(response.strip(), self.format)
|
||||||
|
except ValueError as e:
|
||||||
|
raise OutputParserException(
|
||||||
|
f"Could not parse datetime string: {response}"
|
||||||
|
) from e
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _type(self) -> str:
|
||||||
|
return "datetime"
|
@ -0,0 +1,49 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from langchain.output_parsers.datetime import DatetimeOutputParser
|
||||||
|
|
||||||
|
|
||||||
|
def test_datetime_output_parser_parse() -> None:
|
||||||
|
parser = DatetimeOutputParser()
|
||||||
|
|
||||||
|
# Test valid input
|
||||||
|
date = datetime.now()
|
||||||
|
datestr = date.strftime(parser.format)
|
||||||
|
result = parser.parse(datestr)
|
||||||
|
assert result == date
|
||||||
|
|
||||||
|
# Test valid input
|
||||||
|
parser.format = "%Y-%m-%dT%H:%M:%S"
|
||||||
|
date = datetime.now()
|
||||||
|
datestr = date.strftime(parser.format)
|
||||||
|
result = parser.parse(datestr)
|
||||||
|
assert (
|
||||||
|
result.year == date.year
|
||||||
|
and result.month == date.month
|
||||||
|
and result.day == date.day
|
||||||
|
and result.hour == date.hour
|
||||||
|
and result.minute == date.minute
|
||||||
|
and result.second == date.second
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test valid input
|
||||||
|
parser.format = "%H:%M:%S"
|
||||||
|
date = datetime.now()
|
||||||
|
datestr = date.strftime(parser.format)
|
||||||
|
result = parser.parse(datestr)
|
||||||
|
assert (
|
||||||
|
result.hour == date.hour
|
||||||
|
and result.minute == date.minute
|
||||||
|
and result.second == date.second
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test invalid input
|
||||||
|
try:
|
||||||
|
sleep(0.001)
|
||||||
|
datestr = date.strftime(parser.format)
|
||||||
|
result = parser.parse(datestr)
|
||||||
|
assert result == date
|
||||||
|
assert False, "Should have raised AssertionError"
|
||||||
|
except AssertionError:
|
||||||
|
pass
|
Loading…
Reference in New Issue