flowllm 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. flowllm/__init__.py +21 -0
  2. flowllm/app.py +15 -0
  3. flowllm/client/__init__.py +25 -0
  4. flowllm/client/async_http_client.py +81 -0
  5. flowllm/client/http_client.py +81 -0
  6. flowllm/client/mcp_client.py +133 -0
  7. flowllm/client/sync_mcp_client.py +116 -0
  8. flowllm/config/__init__.py +1 -0
  9. flowllm/config/default.yaml +77 -0
  10. flowllm/config/empty.yaml +37 -0
  11. flowllm/config/pydantic_config_parser.py +242 -0
  12. flowllm/context/base_context.py +79 -0
  13. flowllm/context/flow_context.py +16 -0
  14. llmflow/op/prompt_mixin.py → flowllm/context/prompt_handler.py +25 -14
  15. flowllm/context/registry.py +30 -0
  16. flowllm/context/service_context.py +147 -0
  17. flowllm/embedding_model/__init__.py +1 -0
  18. {llmflow → flowllm}/embedding_model/base_embedding_model.py +93 -2
  19. {llmflow → flowllm}/embedding_model/openai_compatible_embedding_model.py +71 -13
  20. flowllm/flow/__init__.py +1 -0
  21. flowllm/flow/base_flow.py +72 -0
  22. flowllm/flow/base_tool_flow.py +15 -0
  23. flowllm/flow/gallery/__init__.py +8 -0
  24. flowllm/flow/gallery/cmd_flow.py +11 -0
  25. flowllm/flow/gallery/code_tool_flow.py +30 -0
  26. flowllm/flow/gallery/dashscope_search_tool_flow.py +34 -0
  27. flowllm/flow/gallery/deepsearch_tool_flow.py +39 -0
  28. flowllm/flow/gallery/expression_tool_flow.py +18 -0
  29. flowllm/flow/gallery/mock_tool_flow.py +67 -0
  30. flowllm/flow/gallery/tavily_search_tool_flow.py +30 -0
  31. flowllm/flow/gallery/terminate_tool_flow.py +30 -0
  32. flowllm/flow/parser/expression_parser.py +171 -0
  33. flowllm/llm/__init__.py +2 -0
  34. {llmflow → flowllm}/llm/base_llm.py +100 -18
  35. flowllm/llm/litellm_llm.py +455 -0
  36. flowllm/llm/openai_compatible_llm.py +439 -0
  37. flowllm/op/__init__.py +11 -0
  38. llmflow/op/react/react_v1_op.py → flowllm/op/agent/react_op.py +17 -22
  39. flowllm/op/akshare/__init__.py +3 -0
  40. flowllm/op/akshare/get_ak_a_code_op.py +108 -0
  41. flowllm/op/akshare/get_ak_a_code_prompt.yaml +21 -0
  42. flowllm/op/akshare/get_ak_a_info_op.py +140 -0
  43. flowllm/op/base_llm_op.py +64 -0
  44. flowllm/op/base_op.py +148 -0
  45. flowllm/op/base_ray_op.py +313 -0
  46. flowllm/op/code/__init__.py +1 -0
  47. flowllm/op/code/execute_code_op.py +42 -0
  48. flowllm/op/gallery/__init__.py +2 -0
  49. flowllm/op/gallery/mock_op.py +42 -0
  50. flowllm/op/gallery/terminate_op.py +29 -0
  51. flowllm/op/parallel_op.py +23 -0
  52. flowllm/op/search/__init__.py +3 -0
  53. flowllm/op/search/dashscope_deep_research_op.py +260 -0
  54. flowllm/op/search/dashscope_search_op.py +179 -0
  55. flowllm/op/search/dashscope_search_prompt.yaml +13 -0
  56. flowllm/op/search/tavily_search_op.py +102 -0
  57. flowllm/op/sequential_op.py +21 -0
  58. flowllm/schema/flow_request.py +12 -0
  59. flowllm/schema/flow_response.py +12 -0
  60. flowllm/schema/message.py +35 -0
  61. flowllm/schema/service_config.py +72 -0
  62. flowllm/schema/tool_call.py +118 -0
  63. {llmflow → flowllm}/schema/vector_node.py +1 -0
  64. flowllm/service/__init__.py +3 -0
  65. flowllm/service/base_service.py +68 -0
  66. flowllm/service/cmd_service.py +15 -0
  67. flowllm/service/http_service.py +79 -0
  68. flowllm/service/mcp_service.py +47 -0
  69. flowllm/storage/__init__.py +1 -0
  70. flowllm/storage/cache/__init__.py +1 -0
  71. flowllm/storage/cache/cache_data_handler.py +104 -0
  72. flowllm/storage/cache/data_cache.py +375 -0
  73. flowllm/storage/vector_store/__init__.py +3 -0
  74. flowllm/storage/vector_store/base_vector_store.py +44 -0
  75. {llmflow → flowllm/storage}/vector_store/chroma_vector_store.py +11 -10
  76. {llmflow → flowllm/storage}/vector_store/es_vector_store.py +11 -11
  77. llmflow/vector_store/file_vector_store.py → flowllm/storage/vector_store/local_vector_store.py +110 -11
  78. flowllm/utils/common_utils.py +52 -0
  79. flowllm/utils/fetch_url.py +117 -0
  80. flowllm/utils/llm_utils.py +28 -0
  81. flowllm/utils/ridge_v2.py +54 -0
  82. {llmflow → flowllm}/utils/timer.py +5 -4
  83. {flowllm-0.1.0.dist-info → flowllm-0.1.2.dist-info}/METADATA +45 -388
  84. flowllm-0.1.2.dist-info/RECORD +99 -0
  85. flowllm-0.1.2.dist-info/entry_points.txt +2 -0
  86. {flowllm-0.1.0.dist-info → flowllm-0.1.2.dist-info}/licenses/LICENSE +1 -1
  87. flowllm-0.1.2.dist-info/top_level.txt +1 -0
  88. flowllm-0.1.0.dist-info/RECORD +0 -66
  89. flowllm-0.1.0.dist-info/entry_points.txt +0 -3
  90. flowllm-0.1.0.dist-info/top_level.txt +0 -1
  91. llmflow/app.py +0 -53
  92. llmflow/config/config_parser.py +0 -80
  93. llmflow/config/mock_config.yaml +0 -58
  94. llmflow/embedding_model/__init__.py +0 -5
  95. llmflow/enumeration/agent_state.py +0 -8
  96. llmflow/llm/__init__.py +0 -5
  97. llmflow/llm/openai_compatible_llm.py +0 -283
  98. llmflow/mcp_server.py +0 -110
  99. llmflow/op/__init__.py +0 -10
  100. llmflow/op/base_op.py +0 -125
  101. llmflow/op/mock_op.py +0 -40
  102. llmflow/op/vector_store/__init__.py +0 -13
  103. llmflow/op/vector_store/recall_vector_store_op.py +0 -48
  104. llmflow/op/vector_store/update_vector_store_op.py +0 -28
  105. llmflow/op/vector_store/vector_store_action_op.py +0 -46
  106. llmflow/pipeline/pipeline.py +0 -94
  107. llmflow/pipeline/pipeline_context.py +0 -37
  108. llmflow/schema/app_config.py +0 -69
  109. llmflow/schema/experience.py +0 -144
  110. llmflow/schema/message.py +0 -68
  111. llmflow/schema/request.py +0 -32
  112. llmflow/schema/response.py +0 -29
  113. llmflow/service/__init__.py +0 -0
  114. llmflow/service/llmflow_service.py +0 -96
  115. llmflow/tool/__init__.py +0 -9
  116. llmflow/tool/base_tool.py +0 -80
  117. llmflow/tool/code_tool.py +0 -43
  118. llmflow/tool/dashscope_search_tool.py +0 -162
  119. llmflow/tool/mcp_tool.py +0 -77
  120. llmflow/tool/tavily_search_tool.py +0 -109
  121. llmflow/tool/terminate_tool.py +0 -23
  122. llmflow/utils/__init__.py +0 -0
  123. llmflow/utils/common_utils.py +0 -17
  124. llmflow/utils/file_handler.py +0 -25
  125. llmflow/utils/http_client.py +0 -156
  126. llmflow/utils/op_utils.py +0 -102
  127. llmflow/utils/registry.py +0 -33
  128. llmflow/vector_store/__init__.py +0 -7
  129. llmflow/vector_store/base_vector_store.py +0 -136
  130. {llmflow → flowllm/context}/__init__.py +0 -0
  131. {llmflow/config → flowllm/enumeration}/__init__.py +0 -0
  132. {llmflow → flowllm}/enumeration/chunk_enum.py +0 -0
  133. {llmflow → flowllm}/enumeration/http_enum.py +0 -0
  134. {llmflow → flowllm}/enumeration/role.py +0 -0
  135. {llmflow/enumeration → flowllm/flow/parser}/__init__.py +0 -0
  136. {llmflow/op/react → flowllm/op/agent}/__init__.py +0 -0
  137. /llmflow/op/react/react_v1_prompt.yaml → /flowllm/op/agent/react_prompt.yaml +0 -0
  138. {llmflow/pipeline → flowllm/schema}/__init__.py +0 -0
  139. {llmflow/schema → flowllm/utils}/__init__.py +0 -0
  140. {llmflow → flowllm}/utils/singleton.py +0 -0
  141. {flowllm-0.1.0.dist-info → flowllm-0.1.2.dist-info}/WHEEL +0 -0
llmflow/op/base_op.py DELETED
@@ -1,125 +0,0 @@
1
- from abc import abstractmethod, ABC
2
- from concurrent.futures import Future
3
- from pathlib import Path
4
- from typing import List
5
-
6
- from loguru import logger
7
- from tqdm import tqdm
8
-
9
- from llmflow.embedding_model import EMBEDDING_MODEL_REGISTRY
10
- from llmflow.embedding_model.base_embedding_model import BaseEmbeddingModel
11
- from llmflow.llm import LLM_REGISTRY
12
- from llmflow.llm.base_llm import BaseLLM
13
- from llmflow.op.prompt_mixin import PromptMixin
14
- from llmflow.pipeline.pipeline_context import PipelineContext
15
- from llmflow.schema.app_config import OpConfig, LLMConfig, EmbeddingModelConfig
16
- from llmflow.utils.common_utils import camel_to_snake
17
- from llmflow.utils.timer import Timer
18
- from llmflow.vector_store.base_vector_store import BaseVectorStore
19
-
20
-
21
- class BaseOp(PromptMixin, ABC):
22
- current_path: str = __file__
23
-
24
- def __init__(self, context: PipelineContext, op_config: OpConfig):
25
- super().__init__()
26
- self.context: PipelineContext = context
27
- self.op_config: OpConfig = op_config
28
- self.timer = Timer(name=self.simple_name)
29
-
30
- self._prepare_prompt()
31
-
32
- self._llm: BaseLLM | None = None
33
- self._embedding_model: BaseEmbeddingModel | None = None
34
- self._vector_store: BaseVectorStore | None = None
35
-
36
- self.task_list: List[Future] = []
37
-
38
- def _prepare_prompt(self):
39
- if self.op_config.prompt_file_path:
40
- prompt_file_path = self.op_config.prompt_file_path
41
- else:
42
- prompt_name = self.simple_name.replace("_op", "_prompt.yaml")
43
- prompt_file_path = Path(self.current_path).parent / prompt_name
44
-
45
- # Load custom prompts from prompt file
46
- self.load_prompt_by_file(prompt_file_path=prompt_file_path)
47
-
48
- # Load custom prompts from config
49
- self.load_prompt_dict(prompt_dict=self.op_config.prompt_dict)
50
-
51
- @property
52
- def simple_name(self) -> str:
53
- return camel_to_snake(self.__class__.__name__)
54
-
55
- @property
56
- def op_params(self) -> dict:
57
- return self.op_config.params
58
-
59
- @abstractmethod
60
- def execute(self):
61
- ...
62
-
63
- def execute_wrap(self):
64
- try:
65
- with self.timer:
66
- return self.execute()
67
-
68
- except Exception as e:
69
- logger.exception(f"op={self.simple_name} execute failed, error={e.args}")
70
-
71
- def submit_task(self, fn, *args, **kwargs):
72
- task = self.context.thread_pool.submit(fn, *args, **kwargs)
73
- self.task_list.append(task)
74
- return self
75
-
76
- def join_task(self, task_desc: str = None) -> list:
77
- result = []
78
- for task in tqdm(self.task_list, desc=task_desc or (self.simple_name + ".join_task")):
79
- t_result = task.result()
80
- if t_result:
81
- if isinstance(t_result, list):
82
- result.extend(t_result)
83
- else:
84
- result.append(t_result)
85
- self.task_list.clear()
86
- return result
87
-
88
- @property
89
- def llm(self) -> BaseLLM:
90
- if self._llm is None:
91
- llm_name: str = self.op_config.llm
92
- assert llm_name in self.context.app_config.llm, f"llm={llm_name} not found in app_config.llm!"
93
- llm_config: LLMConfig = self.context.app_config.llm[llm_name]
94
-
95
- assert llm_config.backend in LLM_REGISTRY, f"llm.backend={llm_config.backend} not found in LLM_REGISTRY!"
96
- llm_cls = LLM_REGISTRY[llm_config.backend]
97
- self._llm = llm_cls(model_name=llm_config.model_name, **llm_config.params)
98
-
99
- return self._llm
100
-
101
- @property
102
- def embedding_model(self):
103
- if self._embedding_model is None:
104
- embedding_model_name: str = self.op_config.embedding_model
105
- assert embedding_model_name in self.context.app_config.embedding_model, \
106
- f"embedding_model={embedding_model_name} not found in app_config.embedding_model!"
107
- embedding_model_config: EmbeddingModelConfig = self.context.app_config.embedding_model[embedding_model_name]
108
-
109
- assert embedding_model_config.backend in EMBEDDING_MODEL_REGISTRY, \
110
- f"embedding_model.backend={embedding_model_config.backend} not found in EMBEDDING_MODEL_REGISTRY!"
111
- embedding_model_cls = EMBEDDING_MODEL_REGISTRY[embedding_model_config.backend]
112
- self._embedding_model = embedding_model_cls(model_name=embedding_model_config.model_name,
113
- **embedding_model_config.params)
114
-
115
- return self._embedding_model
116
-
117
- @property
118
- def vector_store(self):
119
- if self._vector_store is None:
120
- vector_store_name: str = self.op_config.vector_store
121
- assert vector_store_name in self.context.vector_store_dict, \
122
- f"vector_store={vector_store_name} not found in vector_store_dict!"
123
- self._vector_store = self.context.vector_store_dict[vector_store_name]
124
-
125
- return self._vector_store
llmflow/op/mock_op.py DELETED
@@ -1,40 +0,0 @@
1
- import time
2
-
3
- from loguru import logger
4
-
5
- from llmflow.op import OP_REGISTRY
6
- from llmflow.op.base_op import BaseOp
7
-
8
-
9
- @OP_REGISTRY.register()
10
- class Mock1Op(BaseOp):
11
- def execute(self):
12
- time.sleep(1)
13
- a: int = self.op_params["a"]
14
- b: str = self.op_params["b"]
15
- logger.info(f"enter class={self.simple_name}. a={a} b={b}")
16
-
17
-
18
- @OP_REGISTRY.register()
19
- class Mock2Op(Mock1Op):
20
- ...
21
-
22
-
23
- @OP_REGISTRY.register()
24
- class Mock3Op(Mock1Op):
25
- ...
26
-
27
-
28
- @OP_REGISTRY.register()
29
- class Mock4Op(Mock1Op):
30
- ...
31
-
32
-
33
- @OP_REGISTRY.register()
34
- class Mock5Op(Mock1Op):
35
- ...
36
-
37
-
38
- @OP_REGISTRY.register()
39
- class Mock6Op(Mock1Op):
40
- ...
@@ -1,13 +0,0 @@
1
- """
2
- 1. retrieve:
3
- search: query(context), workspace_id(request), top_k(request)
4
- 2. summary:
5
- insert: nodes(context), workspace_id(request)
6
- delete: ids(context), workspace_id(request)
7
- search: query(context), workspace_id(request), top_k(request.config.op)
8
- 3. vector:
9
- dump: workspace_id(request), path(str), max_size(int)
10
- load: workspace_id(request), path(str)
11
- delete: workspace_id(request)
12
- copy: source_id, target_id, max_size(int)
13
- """
@@ -1,48 +0,0 @@
1
- from typing import List
2
-
3
- from loguru import logger
4
-
5
- from llmflow.op import OP_REGISTRY
6
- from llmflow.op.base_op import BaseOp
7
- from llmflow.schema.experience import BaseExperience, vector_node_to_experience
8
- from llmflow.schema.request import RetrieverRequest
9
- from llmflow.schema.response import RetrieverResponse
10
- from llmflow.schema.vector_node import VectorNode
11
-
12
-
13
- @OP_REGISTRY.register()
14
- class RecallVectorStoreOp(BaseOp):
15
- SEARCH_QUERY = "search_query"
16
- SEARCH_MESSAGE = "search_message"
17
-
18
- def execute(self):
19
- # get query
20
- query = self.context.get_context(self.SEARCH_QUERY)
21
- assert query, "query should be not empty!"
22
-
23
- # retrieve from vector store
24
- request: RetrieverRequest = self.context.request
25
- nodes: List[VectorNode] = self.vector_store.search(query=query,
26
- workspace_id=request.workspace_id,
27
- top_k=request.top_k)
28
-
29
- # convert to experience, filter duplicate
30
- experience_list: List[BaseExperience] = []
31
- experience_content_list: List[str] = []
32
- for node in nodes:
33
- experience: BaseExperience = vector_node_to_experience(node)
34
- if experience.content not in experience_content_list:
35
- experience_list.append(experience)
36
- experience_content_list.append(experience.content)
37
- experience_size = len(experience_list)
38
- logger.info(f"retrieve experience size={experience_size}")
39
-
40
- # filter by score
41
- threshold_score: float | None = self.op_params.get("threshold_score", None)
42
- if threshold_score is not None:
43
- experience_list = [e for e in experience_list if e.score >= threshold_score or e.score is None]
44
- logger.info(f"after filter by threshold_score size={len(experience_list)}")
45
-
46
- # set response
47
- response: RetrieverResponse = self.context.response
48
- response.experience_list = experience_list
@@ -1,28 +0,0 @@
1
- import json
2
- from typing import List
3
-
4
- from loguru import logger
5
-
6
- from llmflow.op import OP_REGISTRY
7
- from llmflow.op.base_op import BaseOp
8
- from llmflow.schema.experience import BaseExperience
9
- from llmflow.schema.request import BaseRequest
10
- from llmflow.schema.vector_node import VectorNode
11
-
12
-
13
- @OP_REGISTRY.register()
14
- class UpdateVectorStoreOp(BaseOp):
15
-
16
- def execute(self):
17
- request: BaseRequest = self.context.request
18
-
19
- experience_ids: List[str] | None = self.context.response.deleted_experience_ids
20
- if experience_ids:
21
- self.vector_store.delete(node_ids=experience_ids, workspace_id=request.workspace_id)
22
- logger.info(f"delete experience_ids={json.dumps(experience_ids, indent=2)}")
23
-
24
- insert_experience_list: List[BaseExperience] | None = self.context.response.experience_list
25
- if insert_experience_list:
26
- insert_nodes: List[VectorNode] = [x.to_vector_node() for x in insert_experience_list]
27
- self.vector_store.insert(nodes=insert_nodes, workspace_id=request.workspace_id)
28
- logger.info(f"insert insert_node.size={len(insert_nodes)}")
@@ -1,46 +0,0 @@
1
- from llmflow.op import OP_REGISTRY
2
- from llmflow.op.base_op import BaseOp
3
- from llmflow.schema.experience import vector_node_to_experience, dict_to_experience, BaseExperience
4
- from llmflow.schema.request import VectorStoreRequest
5
- from llmflow.schema.response import VectorStoreResponse
6
- from llmflow.schema.vector_node import VectorNode
7
-
8
-
9
- @OP_REGISTRY.register()
10
- class VectorStoreActionOp(BaseOp):
11
-
12
- def execute(self):
13
- request: VectorStoreRequest = self.context.request
14
- response: VectorStoreResponse = self.context.response
15
-
16
- if request.action == "copy":
17
- result = self.vector_store.copy_workspace(src_workspace_id=request.src_workspace_id,
18
- dest_workspace_id=request.workspace_id)
19
-
20
- elif request.action == "delete":
21
- result = self.vector_store.delete_workspace(workspace_id=request.workspace_id)
22
-
23
- elif request.action == "dump":
24
- def node_to_experience(node: VectorNode) -> dict:
25
- return vector_node_to_experience(node).model_dump()
26
-
27
- result = self.vector_store.dump_workspace(workspace_id=request.workspace_id,
28
- path=request.path,
29
- callback_fn=node_to_experience)
30
-
31
- elif request.action == "load":
32
- def experience_dict_to_node(experience_dict: dict) -> VectorNode:
33
- experience: BaseExperience = dict_to_experience(experience_dict=experience_dict)
34
- return experience.to_vector_node()
35
-
36
- result = self.vector_store.load_workspace(workspace_id=request.workspace_id,
37
- path=request.path,
38
- callback_fn=experience_dict_to_node)
39
-
40
- else:
41
- raise ValueError(f"invalid action={request.action}")
42
-
43
- if isinstance(result, dict):
44
- response.metadata.update(result)
45
- else:
46
- response.metadata["result"] = str(result)
@@ -1,94 +0,0 @@
1
- from concurrent.futures import as_completed
2
- from itertools import zip_longest
3
- from typing import List
4
-
5
- from loguru import logger
6
-
7
- from llmflow.op import OP_REGISTRY
8
- from llmflow.op.base_op import BaseOp
9
- from llmflow.pipeline.pipeline_context import PipelineContext
10
- from llmflow.utils.timer import Timer, timer
11
-
12
-
13
- class Pipeline:
14
- seq_symbol: str = "->"
15
- parallel_symbol: str = "|"
16
-
17
- def __init__(self, pipeline: str, context: PipelineContext):
18
- self.pipeline_list: List[str | List[str]] = self._parse_pipline(pipeline)
19
- self.context: PipelineContext = context
20
-
21
- def _parse_pipline(self, pipeline: str) -> List[str | List[str]]:
22
- pipeline_list: List[str | List[str]] = []
23
-
24
- for pipeline_split1 in pipeline.split("["):
25
- for sub_pipeline in pipeline_split1.split("]"):
26
- sub_pipeline = sub_pipeline.strip().strip(self.seq_symbol)
27
- if not sub_pipeline:
28
- continue
29
-
30
- if self.parallel_symbol in sub_pipeline:
31
- pipeline_list.append(sub_pipeline.split(self.parallel_symbol))
32
- else:
33
- pipeline_list.append(sub_pipeline)
34
- logger.info(f"add sub_pipeline={sub_pipeline}")
35
- return pipeline_list
36
-
37
- def _execute_sub_pipeline(self, pipeline: str):
38
- op_config_dict = self.context.app_config.op
39
- for op in pipeline.split(self.seq_symbol):
40
- op = op.strip()
41
- if not op:
42
- continue
43
-
44
- assert op in op_config_dict, f"op={op} config is missing!"
45
- op_config = op_config_dict[op]
46
-
47
- assert op_config.backend in OP_REGISTRY, f"op={op} backend={op_config.backend} is not registered!"
48
- op_cls = OP_REGISTRY[op_config.backend]
49
-
50
- op_obj: BaseOp = op_cls(context=self.context, op_config=op_config)
51
- op_obj.execute_wrap()
52
-
53
- def _parse_sub_pipeline(self, pipeline: str):
54
- for op in pipeline.split(self.seq_symbol):
55
- op = op.strip()
56
- if not op:
57
- continue
58
-
59
- yield op
60
-
61
- def print_pipeline(self):
62
- i: int = 0
63
- for pipeline in self.pipeline_list:
64
- if isinstance(pipeline, str):
65
- for op in self._parse_sub_pipeline(pipeline):
66
- i += 1
67
- logger.info(f"stage_{i}: {op}")
68
-
69
- elif isinstance(pipeline, list):
70
- parallel_pipeline = [self._parse_sub_pipeline(x) for x in pipeline]
71
- for op_list in zip_longest(*parallel_pipeline, fillvalue="-"):
72
- i += 1
73
- logger.info(f"stage{i}: {' | '.join(op_list)}")
74
- else:
75
- raise ValueError(f"unknown pipeline.type={type(pipeline)}")
76
-
77
- @timer(name="pipeline.execute")
78
- def __call__(self, enable_print: bool = True):
79
- if enable_print:
80
- self.print_pipeline()
81
-
82
- for i, pipeline in enumerate(self.pipeline_list):
83
- with Timer(f"step_{i}"):
84
- if isinstance(pipeline, str):
85
- self._execute_sub_pipeline(pipeline)
86
-
87
- else:
88
- future_list = []
89
- for sub_pipeline in pipeline:
90
- future = self.context.thread_pool.submit(self._execute_sub_pipeline, pipeline=sub_pipeline)
91
- future_list.append(future)
92
-
93
- for future in as_completed(future_list):
94
- future.result()
@@ -1,37 +0,0 @@
1
- from concurrent.futures import ThreadPoolExecutor
2
- from typing import Dict
3
-
4
- from llmflow.schema.app_config import AppConfig
5
- from llmflow.vector_store.base_vector_store import BaseVectorStore
6
-
7
-
8
- class PipelineContext:
9
-
10
- def __init__(self, **kwargs):
11
- self._context: dict = {**kwargs}
12
-
13
- def get_context(self, key: str, default=None):
14
- return self._context.get(key, default)
15
-
16
- def set_context(self, key: str, value):
17
- self._context[key] = value
18
-
19
- @property
20
- def request(self):
21
- return self._context["request"]
22
-
23
- @property
24
- def response(self):
25
- return self._context["response"]
26
-
27
- @property
28
- def app_config(self) -> AppConfig:
29
- return self._context["app_config"]
30
-
31
- @property
32
- def thread_pool(self) -> ThreadPoolExecutor:
33
- return self._context["thread_pool"]
34
-
35
- @property
36
- def vector_store_dict(self) -> Dict[str, BaseVectorStore]:
37
- return self._context["vector_store_dict"]
@@ -1,69 +0,0 @@
1
- from dataclasses import dataclass, field
2
- from typing import Dict
3
-
4
-
5
- @dataclass
6
- class HttpServiceConfig:
7
- host: str = field(default="0.0.0.0")
8
- port: int = field(default=8001)
9
- timeout_keep_alive: int = field(default=600)
10
- limit_concurrency: int = field(default=64)
11
-
12
-
13
- @dataclass
14
- class ThreadPoolConfig:
15
- max_workers: int = field(default=10)
16
-
17
-
18
- @dataclass
19
- class APIConfig:
20
- retriever: str = field(default="")
21
- summarizer: str = field(default="")
22
- vector_store: str = field(default="")
23
- agent: str = field(default="")
24
-
25
-
26
- @dataclass
27
- class OpConfig:
28
- backend: str = field(default="")
29
- prompt_file_path: str = field(default="")
30
- prompt_dict: dict = field(default_factory=dict)
31
- llm: str = field(default="")
32
- embedding_model: str = field(default="")
33
- vector_store: str = field(default="")
34
- params: dict = field(default_factory=dict)
35
-
36
-
37
- @dataclass
38
- class LLMConfig:
39
- backend: str = field(default="")
40
- model_name: str = field(default="")
41
- params: dict = field(default_factory=dict)
42
-
43
-
44
- @dataclass
45
- class EmbeddingModelConfig:
46
- backend: str = field(default="")
47
- model_name: str = field(default="")
48
- params: dict = field(default_factory=dict)
49
-
50
-
51
- @dataclass
52
- class VectorStoreConfig:
53
- backend: str = field(default="")
54
- embedding_model: str = field(default="")
55
- params: dict = field(default_factory=dict)
56
-
57
-
58
- @dataclass
59
- class AppConfig:
60
- pre_defined_config: str = field(default="mock_config")
61
- config_path: str = field(default="")
62
- mcp_transport: str = field(default="sse")
63
- http_service: HttpServiceConfig = field(default_factory=HttpServiceConfig)
64
- thread_pool: ThreadPoolConfig = field(default_factory=ThreadPoolConfig)
65
- api: APIConfig = field(default_factory=APIConfig)
66
- op: Dict[str, OpConfig] = field(default_factory=dict)
67
- llm: Dict[str, LLMConfig] = field(default_factory=dict)
68
- embedding_model: Dict[str, EmbeddingModelConfig] = field(default_factory=dict)
69
- vector_store: Dict[str, VectorStoreConfig] = field(default_factory=dict)
@@ -1,144 +0,0 @@
1
- import datetime
2
- from abc import ABC
3
- from typing import List
4
- from uuid import uuid4
5
-
6
- from loguru import logger
7
- from pydantic import BaseModel, Field
8
-
9
- from llmflow.schema.vector_node import VectorNode
10
-
11
-
12
- class ExperienceMeta(BaseModel):
13
- author: str = Field(default="")
14
- created_time: str = Field(default_factory=lambda: datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
15
- modified_time: str = Field(default_factory=lambda: datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
16
- extra_info: dict | None = Field(default=None)
17
-
18
- def update_modified_time(self):
19
- self.modified_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
20
-
21
-
22
- class BaseExperience(BaseModel, ABC):
23
- workspace_id: str = Field(default="")
24
-
25
- experience_id: str = Field(default_factory=lambda: uuid4().hex)
26
- experience_type: str = Field(default="")
27
-
28
- when_to_use: str = Field(default="")
29
- content: str | bytes = Field(default="")
30
- score: float | None = Field(default=None)
31
- metadata: ExperienceMeta = Field(default_factory=ExperienceMeta)
32
-
33
- def to_vector_node(self) -> VectorNode:
34
- raise NotImplementedError
35
-
36
- @classmethod
37
- def from_vector_node(cls, node: VectorNode):
38
- raise NotImplementedError
39
-
40
-
41
- class TextExperience(BaseExperience):
42
- experience_type: str = Field(default="text")
43
-
44
- def to_vector_node(self) -> VectorNode:
45
- return VectorNode(unique_id=self.experience_id,
46
- workspace_id=self.workspace_id,
47
- content=self.when_to_use,
48
- metadata={
49
- "experience_type": self.experience_type,
50
- "experience_content": self.content,
51
- "score": self.score,
52
- "metadata": self.metadata.model_dump(),
53
- })
54
-
55
- @classmethod
56
- def from_vector_node(cls, node: VectorNode):
57
- return cls(workspace_id=node.workspace_id,
58
- experience_id=node.unique_id,
59
- experience_type=node.metadata.get("experience_type"),
60
- when_to_use=node.content,
61
- content=node.metadata.get("experience_content"),
62
- score=node.metadata.get("score"),
63
- metadata=node.metadata.get("metadata"))
64
-
65
-
66
- class FunctionArg(BaseModel):
67
- arg_name: str = Field(default=...)
68
- arg_type: str = Field(default=...)
69
- required: bool = Field(default=True)
70
-
71
-
72
- class Function(BaseModel):
73
- func_code: str = Field(default=..., description="function code")
74
- func_name: str = Field(default=..., description="function name")
75
- func_args: List[FunctionArg] = Field(default_factory=list)
76
-
77
-
78
- class FuncExperience(BaseExperience):
79
- experience_type: str = Field(default="function")
80
- functions: List[Function] = Field(default_factory=list)
81
-
82
-
83
- class PersonalExperience(BaseExperience):
84
- experience_type: str = Field(default="personal")
85
- person: str = Field(default="")
86
- topic: str = Field(default="")
87
-
88
-
89
- class KnowledgeExperience(BaseExperience):
90
- experience_type: str = Field(default="knowledge")
91
- topic: str = Field(default="")
92
-
93
-
94
- def vector_node_to_experience(node: VectorNode) -> BaseExperience:
95
- experience_type = node.metadata.get("experience_type")
96
- if experience_type == "text":
97
- return TextExperience.from_vector_node(node)
98
-
99
- elif experience_type == "function":
100
- return FuncExperience.from_vector_node(node)
101
-
102
- elif experience_type == "personal":
103
- return PersonalExperience.from_vector_node(node)
104
-
105
- elif experience_type == "knowledge":
106
- return KnowledgeExperience.from_vector_node(node)
107
-
108
- else:
109
- logger.warning(f"experience type {experience_type} not supported")
110
- return TextExperience.from_vector_node(node)
111
-
112
-
113
- def dict_to_experience(experience_dict: dict) -> BaseExperience:
114
- experience_type = experience_dict.get("experience_type", "text")
115
- if experience_type == "text":
116
- return TextExperience(**experience_dict)
117
-
118
- elif experience_type == "function":
119
- return FuncExperience(**experience_dict)
120
-
121
- elif experience_type == "personal":
122
- return PersonalExperience(**experience_dict)
123
-
124
- elif experience_type == "knowledge":
125
- return KnowledgeExperience(**experience_dict)
126
-
127
- else:
128
- logger.warning(f"experience type {experience_type} not supported")
129
- return TextExperience(**experience_dict)
130
-
131
-
132
- if __name__ == "__main__":
133
- e1 = TextExperience(
134
- workspace_id="w_1024",
135
- experience_id="123",
136
- when_to_use="test case use",
137
- content="test content",
138
- score=0.99,
139
- metadata=ExperienceMeta(author="user"))
140
- print(e1.model_dump_json(indent=2))
141
- v1 = e1.to_vector_node()
142
- print(v1.model_dump_json(indent=2))
143
- e2 = vector_node_to_experience(v1)
144
- print(e2.model_dump_json(indent=2))