aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/infini/core.py22
-rw-r--r--src/infini/exceptions.py4
-rw-r--r--src/infini/generator.py48
-rw-r--r--src/infini/handler.py13
-rw-r--r--src/infini/interceptor.py35
-rw-r--r--src/infini/loader.py26
-rw-r--r--src/infini/output.py6
-rw-r--r--src/infini/register.py30
-rw-r--r--src/infini/typing.py16
9 files changed, 158 insertions, 42 deletions
diff --git a/src/infini/core.py b/src/infini/core.py
index fe99f4b3..7c84a15f 100644
--- a/src/infini/core.py
+++ b/src/infini/core.py
@@ -1,23 +1,23 @@
from infini.input import Input
from infini.interceptor import Interceptor
-from infini.generator import TextGenerator
+from infini.generator import Generator
from infini.handler import Handler
from infini.injector import Injector
from infini.output import Output
-from infini.typing import Any, Generator, Union
+from infini.typing import Any, Generator as GeneratorT, Union
from infini.exceptions import ValueError
class Core:
pre_interceptor: Interceptor
handler: Handler
- generator: TextGenerator
+ generator: Generator
interceptor: Interceptor
injector: Injector
def input(
self, input: Input
- ) -> Generator[Union[str, Output], Any, None]: # TODO 支持Workflow
+ ) -> GeneratorT[Union[str, Output], Any, None]:
for pre_intercepted_stream in self.pre_intercept(input):
if isinstance(pre_intercepted_stream, Output):
if not isinstance(pre_intercepted_stream, Output):
@@ -40,7 +40,7 @@ class Core:
if handled_stream.is_empty():
return
outcome = self.generate(handled_stream)
- for stream in self.intercept(outcome):
+ for stream in self.intercept(handled_stream, outcome):
if isinstance(stream, Output):
if stream.is_empty():
return
@@ -53,10 +53,12 @@ class Core:
if handled_stream.block:
return
- def pre_intercept(self, input: Input) -> Generator[Union[Input, Output], Any, None]:
+ def pre_intercept(
+ self, input: Input
+ ) -> GeneratorT[Union[Input, Output], Any, None]:
return self.pre_interceptor.input(input)
- def handle(self, input: Input) -> Generator[Output, Any, None]:
+ def handle(self, input: Input) -> GeneratorT[Output, Any, None]:
iterator = self.handler.input(input)
for output in iterator:
yield output
@@ -64,5 +66,7 @@ class Core:
def generate(self, output: Output) -> str:
return self.generator.output(output, self.injector)
- def intercept(self, output_text: str) -> Generator[Union[str, Output], Any, None]:
- return self.interceptor.output(output_text)
+ def intercept(
+ self, output: Output, output_text: str
+ ) -> GeneratorT[Union[str, Output], Any, None]:
+ return self.interceptor.output(output, output_text)
diff --git a/src/infini/exceptions.py b/src/infini/exceptions.py
index 37386ce3..2e2b0197 100644
--- a/src/infini/exceptions.py
+++ b/src/infini/exceptions.py
@@ -10,5 +10,9 @@ class UnknownEvent(InfiniException):
"""文本事件不存在"""
+class UnknownEventType(InfiniException, TypeError):
+ """文本事件不存在"""
+
+
class ValueError(InfiniException, ValueError):
"""错误的数据"""
diff --git a/src/infini/generator.py b/src/infini/generator.py
index 5473dade..254f0cdd 100644
--- a/src/infini/generator.py
+++ b/src/infini/generator.py
@@ -1,20 +1,37 @@
from infini.output import Output
-from infini.typing import Dict, Callable, Union
-from infini.exceptions import UnknownEvent
+from infini.typing import Type, Dict, Callable, Union, Optional
+from infini.exceptions import UnknownEvent, UnknownEventType
from infini.injector import Injector
from jinja2 import Template
+import abc
-class TextGenerator: # TODO 兼容多类型事件
+
+class BaseGenerator(metaclass=abc.ABCMeta):
+ type: str
events: Dict[str, str]
global_variables: Dict[str, Union[str, Callable]]
+ @abc.abstractmethod
+ def output(self, output: Output, injector: Injector) -> str:
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def match(self, output: Output) -> Template:
+ raise NotImplementedError
+
+
+class TextGenerator(BaseGenerator):
+ type = "text"
+
def __init__(self) -> None:
self.events = {}
self.global_variables = {}
def output(self, output: Output, injector: Injector) -> str:
- assert output.type == "text", "文本生成器应当传入类型为 'text' 的 Output 实例"
+ assert (
+ output.type == self.type
+ ), f"文本生成器应当传入类型为 '{self.type}' 的 Output 实例"
variables = self.global_variables.copy()
variables.update(output.variables)
for name, variable in variables.items():
@@ -26,3 +43,26 @@ class TextGenerator: # TODO 兼容多类型事件
if context := self.events.get(output.name):
return Template(context)
raise UnknownEvent(f"事件不存在: {output.name}")
+
+
+class Generator:
+ generators: Dict[str, BaseGenerator]
+ events: Dict[str, str]
+ global_variables: Dict[str, Union[str, Callable]]
+
+ def __init__(self) -> None:
+ self.generators = {"text": TextGenerator()}
+
+ def output(self, output: Output, injector: Injector) -> str:
+ assert (
+ output.type != "workflow"
+ ), "生成器应当传入类型为非 'workflow' 的 Output 实例"
+ if not (generator := self.match(output)):
+ raise UnknownEventType(f"没有为事件类型 '{output.type}' 注册生成器")
+
+ generator.events = self.events
+ generator.global_variables = self.global_variables
+ return generator.output(output, injector)
+
+ def match(self, output: Output) -> Optional[BaseGenerator]:
+ return self.generators.get(output.type)
diff --git a/src/infini/handler.py b/src/infini/handler.py
index 0d8d1fe0..3d8cd586 100644
--- a/src/infini/handler.py
+++ b/src/infini/handler.py
@@ -1,3 +1,4 @@
+from infini.injector import Injector
from infini.input import Input
from infini.output import Output
from infini.typing import List, Any, RouterType, Callable, Generator, Union
@@ -11,8 +12,16 @@ class Handler:
if (queue := self.match(input.get_plain_text())).is_empty():
yield Output.empty()
return
+ injector = Injector()
+ parameters = {
+ "input": input,
+ "plain_text": input.get_plain_text(),
+ "user_id": input.get_user_id(),
+ }
while not queue.is_empty():
- if isinstance(stream := queue.pop()(input), Generator):
+ if isinstance(
+ stream := injector.output(queue.pop(), parameters=parameters), Generator
+ ):
for output in stream:
yield output
if output.block:
@@ -24,7 +33,7 @@ class Handler:
def match(
self, text: str
- ) -> EventQueue[Callable[[Input], Union[Output, Generator[Output, Any, None]]]]:
+ ) -> EventQueue[Callable[..., Union[Output, Generator[Output, Any, None]]]]:
queue = EventQueue()
for handler in self.handlers:
diff --git a/src/infini/interceptor.py b/src/infini/interceptor.py
index bffd3f8e..87255ae9 100644
--- a/src/infini/interceptor.py
+++ b/src/infini/interceptor.py
@@ -1,3 +1,4 @@
+from infini.injector import Injector
from infini.input import Input
from infini.output import Output
from infini.typing import List, Any, RouterType, Callable, Generator, Union
@@ -9,8 +10,17 @@ class Interceptor:
def input(self, input: Input) -> Generator[Union[Output, Input], Any, None]:
queue = self.match(input.get_plain_text())
+ injector = Injector()
+ parameters = {
+ "input": input,
+ "plain_text": input.get_plain_text(),
+ "user_id": input.get_user_id(),
+ }
while not queue.is_empty():
- if isinstance(stream := queue.pop()(input), Generator):
+ if isinstance(
+ stream := injector.output(queue.pop(), parameters=parameters),
+ Generator,
+ ):
for outcome in stream:
if isinstance(outcome, Input):
input = outcome
@@ -30,11 +40,22 @@ class Interceptor:
input = stream
yield input
- def output(self, output_text: str) -> Generator[Union[Output, str], Any, None]:
- input = Input(output_text)
- queue = self.match(input.get_plain_text())
+ def output(
+ self, output: Output, output_text: str
+ ) -> Generator[Union[Output, str], Any, None]:
+ input = Input(output_text, variables=output.variables)
+ queue = self.match(output_text)
+ injector = Injector()
+ parameters = {
+ "input": input,
+ "output": output,
+ "plain_text": output_text,
+ "user_id": input.get_user_id(),
+ }
while not queue.is_empty():
- if isinstance(stream := queue.pop()(input), Generator):
+ if isinstance(
+ stream := injector.output(queue.pop(), parameters=parameters), Generator
+ ):
for outcome in stream:
if isinstance(outcome, Input):
input = outcome
@@ -57,9 +78,7 @@ class Interceptor:
def match(
self, text: str
) -> EventQueue[
- Callable[
- [Input], Union[Input, Output, Generator[Union[Input, Output], Any, None]]
- ]
+ Callable[..., Union[Input, Output, Generator[Union[Input, Output], Any, None]]]
]:
queue = EventQueue()
diff --git a/src/infini/loader.py b/src/infini/loader.py
index 061ed8b9..07ebe0a8 100644
--- a/src/infini/loader.py
+++ b/src/infini/loader.py
@@ -1,6 +1,6 @@
from importlib.util import spec_from_file_location
from infini.core import Core
-from infini.generator import TextGenerator
+from infini.generator import BaseGenerator, Generator, TextGenerator
from infini.handler import Handler
from infini.injector import Injector
from infini.interceptor import Interceptor
@@ -81,15 +81,17 @@ class InfiniLoader(importlib.abc.Loader):
exec(Path(self.filename).read_text("utf-8"), vars(module))
-def install():
- sys.meta_path.insert(0, InfiniMetaFinder())
+def _install():
+ if not sys.meta_path:
+ raise OSError("Var 'sys.meta_path' is empty, since Python is stop.")
+ if not isinstance(sys.meta_path[0], InfiniMetaFinder):
+ sys.meta_path.insert(0, InfiniMetaFinder())
-def uninstall():
+def _uninstall():
for meta_path in sys.meta_path:
if isinstance(meta_path, InfiniMetaFinder):
sys.meta_path.remove(meta_path)
- break
class Loader:
@@ -98,6 +100,7 @@ class Loader:
events: Dict[str, str]
global_variables: Dict[str, Union[str, Callable]]
interceptors: List[RouterType]
+ generators: Dict[str, BaseGenerator]
def __init__(self) -> None:
self.pre_interceptors = []
@@ -105,6 +108,7 @@ class Loader:
self.events = {}
self.global_variables = {}
self.interceptors = []
+ self.generators = {}
self.prepare()
def __enter__(self) -> "Loader":
@@ -124,7 +128,7 @@ class Loader:
return register_variables
def prepare(self) -> None:
- install()
+ _install()
def load(self, name: str) -> ModuleType:
self.prepare()
@@ -168,7 +172,7 @@ class Loader:
return list
def close(self):
- uninstall()
+ _uninstall()
def inject_core(self, core: Core):
pre_interceptor = Interceptor()
@@ -176,6 +180,7 @@ class Loader:
generator = TextGenerator()
interceptor = Interceptor()
injector = Injector()
+ generator = Generator()
self.inject_pre_interceptor(pre_interceptor)
self.inject_handler(handler)
@@ -221,12 +226,13 @@ class Loader:
self.inject_handler(handler)
return handler
- def inject_generator(self, generator: TextGenerator):
+ def inject_generator(self, generator: Generator):
generator.events = self.events
generator.global_variables = self.global_variables
+ generator.generators.update(self.generators)
- def into_generator(self) -> TextGenerator:
- generator = TextGenerator()
+ def into_generator(self) -> Generator:
+ generator = Generator()
self.inject_generator(generator)
return generator
diff --git a/src/infini/output.py b/src/infini/output.py
index 73aa5213..13f26d47 100644
--- a/src/infini/output.py
+++ b/src/infini/output.py
@@ -1,8 +1,8 @@
-from infini.typing import Literal, Dict, Any
+from infini.typing import Union, Literal, Dict, Any
class Output:
- type: Literal["null", "text", "workflow"]
+ type: Union[Literal["null", "text", "workflow"], str]
name: str
status: int
block: bool
@@ -11,7 +11,7 @@ class Output:
def __init__(
self,
- type: Literal["null", "text", "workflow"],
+ type: Union[Literal["null", "text", "workflow"], str],
name: str,
*,
status: int = 0,
diff --git a/src/infini/register.py b/src/infini/register.py
index 0586ae7e..0d85c3c0 100644
--- a/src/infini/register.py
+++ b/src/infini/register.py
@@ -1,7 +1,8 @@
+from infini.typing import List, Dict, Any, Callable, RouterType, Optional, Union, Type
from infini.input import Input
from infini.output import Output
from infini.router import Contains, Router
-from infini.typing import List, Dict, Any, Callable, RouterType, Optional, Union
+from infini.generator import BaseGenerator
from functools import wraps
@@ -11,6 +12,7 @@ class Register:
events: Dict[str, str]
global_variables: Dict[str, Union[str, Callable]]
interceptors: List[RouterType]
+ generators: Dict[str, BaseGenerator]
def __init__(self) -> None:
self.pre_interceptors = []
@@ -18,6 +20,7 @@ class Register:
self.events = {}
self.global_variables = {}
self.interceptors = []
+ self.generators = {}
def pre_interceptor(self, router: Union[Router, str], priority: int = 0):
def decorator(func):
@@ -54,9 +57,27 @@ class Register:
return decorator
def regist_textevent(self, name: str, text: str):
+ import warnings
+
+ warnings.warn(
+ "Infini will soon deprecated `regist_textevent`, "
+ "use `register_textevent` instead."
+ )
+ self.events[name] = text
+
+ def register_textevent(self, name: str, text: str):
self.events[name] = text
def regist_variable(self, name: str, data: Any):
+ import warnings
+
+ warnings.warn(
+ "Infini will soon deprecated `regist_variable`, "
+ "use `register_variable` instead."
+ )
+ self.global_variables[name] = data
+
+ def register_variable(self, name: str, data: Any):
self.global_variables[name] = data
def dynamic_variable(self, name: Optional[str] = None):
@@ -86,3 +107,10 @@ class Register:
return wrapper
return decorator
+
+ def register_generator(
+ self, generator: Union[BaseGenerator, Type[BaseGenerator]]
+ ) -> None:
+ if not isinstance(generator, BaseGenerator):
+ generator = generator()
+ self.generators[generator.type] = generator
diff --git a/src/infini/typing.py b/src/infini/typing.py
index 6bac0099..14c219fc 100644
--- a/src/infini/typing.py
+++ b/src/infini/typing.py
@@ -1,7 +1,9 @@
from typing import (
+ TYPE_CHECKING,
Dict as Dict,
List as List,
Any as Any,
+ Type as Type,
Optional as Optional,
Generic as Generic,
Callable as Callable,
@@ -14,14 +16,18 @@ from typing import (
Union,
)
from types import ModuleType as ModuleType, GeneratorType as GeneratorType
-from . import router, input, output
+
+if TYPE_CHECKING:
+ from infini.router import Router
+ from infini.input import Input
+ from infini.output import Output
T = TypeVar("T")
-Stream = Union["input.Input[Any]", "output.Output"]
-OutputGenerator = Generator["output.Output", Any, None]
+Stream = Union["Input[Any]", "Output"]
+OutputGenerator = Generator["Output", Any, None]
class RouterType(TypedDict):
priority: int
- router: router.Router
- handler: Callable[["input.Input"], Union[Stream, OutputGenerator]]
+ router: "Router"
+ handler: Callable[..., Union[Stream, OutputGenerator]]