mirror of
https://github.com/kennethreitz/instructor.git
synced 2026-06-05 22:50:18 +00:00
655df180ec
* add app to citations * working commit * working app * remove types
115 lines
3.6 KiB
Python
115 lines
3.6 KiB
Python
from pydantic import BaseModel, create_model, Field
|
|
from typing import Optional, List, Type, Union
|
|
from openai_function_call import OpenAISchema
|
|
|
|
|
|
class MultiTaskBase:
|
|
task_type = None # type: ignore
|
|
|
|
@classmethod
|
|
def from_streaming_response(cls, completion):
|
|
json_chunks = cls.extract_json(completion)
|
|
yield from cls.tasks_from_chunks(json_chunks)
|
|
|
|
@classmethod
|
|
def tasks_from_chunks(cls, json_chunks):
|
|
started = False
|
|
potential_object = ""
|
|
for chunk in json_chunks:
|
|
potential_object += chunk
|
|
if not started:
|
|
if "[" in chunk:
|
|
started = True
|
|
potential_object = chunk[chunk.find("[") + 1 :]
|
|
continue
|
|
|
|
task_json, potential_object = cls.get_object(potential_object, 0)
|
|
if task_json:
|
|
obj = cls.task_type.model_validate_json(task_json) # type: ignore
|
|
yield obj
|
|
|
|
@staticmethod
|
|
def extract_json(completion):
|
|
for chunk in completion:
|
|
delta = chunk["choices"][0]["delta"]
|
|
if "function_call" in delta:
|
|
yield delta["function_call"]["arguments"]
|
|
|
|
@staticmethod
|
|
def get_object(str, stack):
|
|
for i, c in enumerate(str):
|
|
if c == "{":
|
|
stack += 1
|
|
if c == "}":
|
|
stack -= 1
|
|
if stack == 0:
|
|
return str[: i + 1], str[i + 2 :]
|
|
return None, str
|
|
|
|
|
|
def MultiTask(
|
|
subtask_class: Type[BaseModel],
|
|
name: Optional[str] = None,
|
|
description: Optional[str] = None,
|
|
):
|
|
"""
|
|
Dynamically create a MultiTask OpenAISchema that can be used to segment multiple
|
|
tasks given a base class. This creates class that can be used to create a toolkit
|
|
for a specific task, names and descriptions are automatically generated. However
|
|
they can be overridden.
|
|
|
|
Note:
|
|
Using this function is equivalent to creating a class that inherits from
|
|
OpenAISchema and has a list of the subtask class as a field.
|
|
|
|
```python
|
|
class MultiTask(OpenAISchema):
|
|
\"""
|
|
Correct segmentation of `{subtask_class.__name__}` tasks
|
|
\"""
|
|
tasks: List[subtask_class] = Field(
|
|
default_factory=list,
|
|
repr=False,
|
|
description=f"Correctly segmented list of `{subtask_class.__name__}` tasks",
|
|
)
|
|
```
|
|
|
|
Parameters:
|
|
subtask_class (Type[OpenAISchema]): The base class to use for the MultiTask
|
|
name (Optional[str]): The name of the MultiTask class, if None then the name
|
|
of the subtask class is used as `Multi{subtask_class.__name__}`
|
|
description (Optional[str]): The description of the MultiTask class, if None
|
|
then the description is set to `Correct segmentation of `{subtask_class.__name__}` tasks`
|
|
|
|
Returns:
|
|
schema (OpenAISchema): A new class that can be used to segment multiple tasks
|
|
"""
|
|
task_name = subtask_class.__name__ if name is None else name
|
|
|
|
name = f"Multi{task_name}"
|
|
|
|
list_tasks = (
|
|
List[subtask_class],
|
|
Field(
|
|
default_factory=list,
|
|
repr=False,
|
|
description=f"Correctly segmented list of `{task_name}` tasks",
|
|
),
|
|
)
|
|
|
|
new_cls = create_model(
|
|
name,
|
|
tasks=list_tasks,
|
|
__base__=(OpenAISchema, MultiTaskBase),
|
|
)
|
|
# set the class constructor BaseModel
|
|
new_cls.task_type = subtask_class
|
|
|
|
new_cls.__doc__ = (
|
|
f"Correct segmentation of `{task_name}` tasks"
|
|
if description is None
|
|
else description
|
|
)
|
|
|
|
return new_cls
|