├── Readme.md ├── aityping └── __init__.py └── setup.py /Readme.md: -------------------------------------------------------------------------------- 1 | # AITyping 2 | 3 | Using AI to "type" (really validate) Python code. Tries to be "Ambient AI". 4 | Allows you to do things like: 5 | 6 | ```python 7 | isinstance("Julia", PersonName) 8 | >>> True 9 | 10 | isinstance("Idaho", PersonName) 11 | >>> False 12 | ``` 13 | 14 | ## 🚀 Overview 15 | 16 | The `typing` module in Python helps the user understand the codebase better. 17 | They are useful for distinguishing between ints and strings, for example. 18 | The `aityping` module helps do "fuzzy typing". 19 | This is really run-time validation. 20 | However, it's bundled up as a type so that you can use it with Pydantic Models easily. 21 | 22 | ## 📄 Installation 23 | `pip install aityping` 24 | 25 | ## 💻 Usage 26 | 27 | ### Setup 28 | 29 | First, you need to set your OpenAI key: 30 | 31 | ```python 32 | import os 33 | os.environ["OPENAI_API_KEY"] = 'YOUR_OPENAI_API_KEY' 34 | ``` 35 | 36 | ### Quickstart 37 | 38 | Next we import the `get_ai_type` function: 39 | 40 | ```python 41 | from aityping import get_ai_type 42 | ``` 43 | 44 | After that is done we can create a "type" with some fuzzy logic 45 | ```python 46 | PersonName = get_ai_type("is a persons name") 47 | ``` 48 | 49 | We can now use this to do type checking as we would with any other type. 50 | 51 | ```python 52 | isinstance("Julia", PersonName) 53 | >>> True 54 | 55 | isinstance("Idaho", PersonName) 56 | >>> False 57 | ``` 58 | 59 | We can also use it to type a Pydantic model and then have that do validation. 60 | ```python 61 | from pydantic import BaseModel 62 | 63 | class Record(BaseModel): 64 | name: PersonName 65 | 66 | Record(name='Julia') 67 | >>> Record(name='Julia') 68 | 69 | Record(name='Idaho') 70 | >>> ValidationError: 1 validation error for Record 71 | >>> name 72 | >>> Flagged as invalid. (type=type_error) 73 | ``` 74 | 75 | ### LLM Configuration 76 | 77 | By default, this will use the following LLM configuration: 78 | 79 | ```python 80 | ChatOpenAI(model="gpt-3.5-turbo", temperature=0) 81 | ``` 82 | 83 | If you want to use a different configuration, you easily can! 84 | 85 | ```python 86 | from langchain.chat_models import ChatOpenAI 87 | PersonName = get_ai_type("is a persons name", llm=ChatOpenAI(model="gpt-4")) 88 | ``` 89 | 90 | -------------------------------------------------------------------------------- /aityping/__init__.py: -------------------------------------------------------------------------------- 1 | from langchain.chains.openai_functions import ( 2 | create_structured_output_chain, 3 | ) 4 | from langchain.chat_models import ChatOpenAI 5 | from langchain.prompts import ( 6 | ChatPromptTemplate, 7 | HumanMessagePromptTemplate, 8 | SystemMessagePromptTemplate, 9 | ) 10 | from pydantic import BaseModel, Field 11 | 12 | 13 | class ValidationResponse(BaseModel): 14 | reasoning: str = Field( 15 | description="Thought process for whether or not the user input is valid." 16 | ) 17 | is_valid: bool = Field( 18 | description="Whether or not the user input is valid according to conditions." 19 | ) 20 | 21 | 22 | class ShortValidationResponse(BaseModel): 23 | is_valid: bool = Field( 24 | description="Whether or not the user input is valid according to conditions." 25 | ) 26 | 27 | 28 | prompt_msgs = [ 29 | SystemMessagePromptTemplate.from_template( 30 | "You need to whether a user's input satisfies the following conditions:\n\n{conditions}" 31 | ), 32 | HumanMessagePromptTemplate.from_template("{input}"), 33 | ] 34 | default_prompt = ChatPromptTemplate(messages=prompt_msgs) 35 | 36 | 37 | def get_ai_type(condition: str, include_reasoning=False, llm=None): 38 | _type = ValidationResponse if include_reasoning else ShortValidationResponse 39 | llm = llm or ChatOpenAI(temperature=0) 40 | chain = create_structured_output_chain(_type, llm, default_prompt) 41 | 42 | class AIMeta(type): 43 | def __instancecheck__(cls, instance): 44 | if instance is None: 45 | return False 46 | check = chain.run(conditions=condition, input=instance) 47 | return check.is_valid 48 | 49 | class AIType(metaclass=AIMeta): 50 | @classmethod 51 | def __get_validators__(cls): 52 | yield cls.validate 53 | 54 | @classmethod 55 | def validate(cls, v): 56 | if v is None: 57 | return False 58 | check = chain.run(conditions=condition, input=v) 59 | if not check.is_valid: 60 | if isinstance(check, ValidationResponse): 61 | raise TypeError(check.reasoning) 62 | else: 63 | raise TypeError("Flagged as invalid.") 64 | return v 65 | 66 | return AIType 67 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name="aityping", 5 | version="0.0.1", 6 | description="Fuzzy type hints with AI.", 7 | packages=find_packages(), 8 | install_requires=[ 9 | "langchain", 10 | "pydantic<2", 11 | ], 12 | ) 13 | --------------------------------------------------------------------------------