flowllm 0.1.2__py3-none-any.whl → 0.1.3__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.
- flowllm/__init__.py +5 -1
- flowllm/context/service_context.py +5 -3
- flowllm/flow/base_flow.py +4 -2
- flowllm/flow/gallery/mock_tool_flow.py +0 -5
- flowllm/flow/gallery/terminate_tool_flow.py +1 -1
- flowllm/llm/litellm_llm.py +2 -1
- flowllm/op/__init__.py +1 -0
- flowllm/op/agent/__init__.py +1 -0
- flowllm/op/agent/{react_op.py → react_v1_op.py} +37 -11
- flowllm/op/agent/{react_prompt.yaml → react_v1_prompt.yaml} +26 -0
- flowllm/op/agent/react_v2_op.py +86 -0
- flowllm/op/agent/react_v2_prompt.yaml +35 -0
- flowllm/op/base_llm_op.py +3 -2
- flowllm/op/base_op.py +26 -9
- flowllm/op/search/dashscope_deep_research_op.py +9 -2
- flowllm/op/search/dashscope_search_op.py +9 -2
- flowllm/op/search/tavily_search_op.py +10 -3
- flowllm/schema/message.py +2 -0
- flowllm/schema/tool_call.py +7 -3
- flowllm/service/http_service.py +2 -2
- flowllm/storage/vector_store/base_vector_store.py +3 -0
- flowllm/storage/vector_store/es_vector_store.py +3 -3
- flowllm/utils/logger_utils.py +28 -0
- {flowllm-0.1.2.dist-info → flowllm-0.1.3.dist-info}/METADATA +1 -1
- {flowllm-0.1.2.dist-info → flowllm-0.1.3.dist-info}/RECORD +29 -26
- {flowllm-0.1.2.dist-info → flowllm-0.1.3.dist-info}/WHEEL +0 -0
- {flowllm-0.1.2.dist-info → flowllm-0.1.3.dist-info}/entry_points.txt +0 -0
- {flowllm-0.1.2.dist-info → flowllm-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {flowllm-0.1.2.dist-info → flowllm-0.1.3.dist-info}/top_level.txt +0 -0
flowllm/__init__.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
import os
|
2
2
|
|
3
|
+
from flowllm.utils.logger_utils import init_logger
|
4
|
+
|
5
|
+
init_logger()
|
6
|
+
|
3
7
|
from flowllm.utils.common_utils import load_env
|
4
8
|
|
5
9
|
load_env()
|
@@ -17,5 +21,5 @@ from flowllm import service
|
|
17
21
|
from flowllm.context.service_context import C
|
18
22
|
from flowllm.op import BaseOp, BaseRayOp, BaseLLMOp
|
19
23
|
|
20
|
-
__version__ = "0.1.
|
24
|
+
__version__ = "0.1.3"
|
21
25
|
|
@@ -39,10 +39,12 @@ class ServiceContext(BaseContext):
|
|
39
39
|
|
40
40
|
self.tool_flow_dict: dict = {}
|
41
41
|
|
42
|
-
def set_default_service_config(self):
|
43
|
-
|
42
|
+
def set_default_service_config(self, parser=None):
|
43
|
+
if parser is None:
|
44
|
+
from flowllm.config.pydantic_config_parser import PydanticConfigParser
|
45
|
+
parser = PydanticConfigParser
|
44
46
|
|
45
|
-
config_parser =
|
47
|
+
config_parser = parser(ServiceConfig)
|
46
48
|
self.service_config = config_parser.parse_args("config=default")
|
47
49
|
return self
|
48
50
|
|
flowllm/flow/base_flow.py
CHANGED
@@ -17,7 +17,7 @@ class BaseFlow(ABC):
|
|
17
17
|
self.name: str = name or camel_to_snake(self.__class__.__name__)
|
18
18
|
self.flow_params: dict = kwargs
|
19
19
|
|
20
|
-
self.flow_op:
|
20
|
+
self.flow_op: BaseOp = self.build_flow()
|
21
21
|
self.print_flow()
|
22
22
|
|
23
23
|
@abstractmethod
|
@@ -55,6 +55,7 @@ class BaseFlow(ABC):
|
|
55
55
|
logger.info(f"{prefix}Operation: {op.name}")
|
56
56
|
|
57
57
|
def return_callback(self, context: FlowContext):
|
58
|
+
logger.info(f"context.response={context.response.model_dump_json()}")
|
58
59
|
return context.response
|
59
60
|
|
60
61
|
def __call__(self, **kwargs) -> FlowResponse:
|
@@ -62,7 +63,8 @@ class BaseFlow(ABC):
|
|
62
63
|
logger.info(f"request.params={kwargs}")
|
63
64
|
|
64
65
|
try:
|
65
|
-
self.
|
66
|
+
flow_op = self.build_flow()
|
67
|
+
flow_op(context=context)
|
66
68
|
|
67
69
|
except Exception as e:
|
68
70
|
logger.exception(f"flow_name={self.name} encounter error={e.args}")
|
@@ -25,11 +25,6 @@ class MockToolFlow(BaseToolFlow):
|
|
25
25
|
"type": "function",
|
26
26
|
"name": "mock_data_processor",
|
27
27
|
"description": "A mock tool that processes data through multiple operations and returns structured results",
|
28
|
-
"arguments": {
|
29
|
-
"input_data": "sample_data",
|
30
|
-
"processing_mode": "advanced",
|
31
|
-
"output_format": "json"
|
32
|
-
},
|
33
28
|
"input_schema": {
|
34
29
|
"input_data": ParamAttrs(
|
35
30
|
type="string",
|
@@ -18,7 +18,7 @@ class TerminateToolFlow(BaseToolFlow):
|
|
18
18
|
"input_schema": {
|
19
19
|
"status": {
|
20
20
|
"type": "str",
|
21
|
-
"description": "
|
21
|
+
"description": "If the user's question can be answered, return success, otherwise return failure.",
|
22
22
|
"required": True,
|
23
23
|
"enum": ["success", "failure"],
|
24
24
|
}
|
flowllm/llm/litellm_llm.py
CHANGED
@@ -2,7 +2,6 @@ import asyncio
|
|
2
2
|
import os
|
3
3
|
from typing import List, Dict
|
4
4
|
|
5
|
-
from litellm import completion, acompletion
|
6
5
|
from loguru import logger
|
7
6
|
from pydantic import Field, PrivateAttr, model_validator
|
8
7
|
|
@@ -98,6 +97,7 @@ class LiteLLMBaseLLM(BaseLLM):
|
|
98
97
|
Yields:
|
99
98
|
Tuple of (chunk_content, ChunkEnum) for each streaming piece
|
100
99
|
"""
|
100
|
+
from litellm import completion
|
101
101
|
for i in range(self.max_retries):
|
102
102
|
try:
|
103
103
|
# Prepare parameters for LiteLLM
|
@@ -200,6 +200,7 @@ class LiteLLMBaseLLM(BaseLLM):
|
|
200
200
|
Yields:
|
201
201
|
Tuple of (chunk_content, ChunkEnum) for each streaming piece
|
202
202
|
"""
|
203
|
+
from litellm import acompletion
|
203
204
|
for i in range(self.max_retries):
|
204
205
|
try:
|
205
206
|
# Prepare parameters for LiteLLM
|
flowllm/op/__init__.py
CHANGED
flowllm/op/agent/__init__.py
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
from .react_v1_op import ReactV1Op
|
@@ -1,32 +1,45 @@
|
|
1
1
|
import datetime
|
2
|
+
import json
|
2
3
|
import time
|
3
4
|
from typing import List, Dict
|
4
5
|
|
5
6
|
from loguru import logger
|
6
7
|
|
7
|
-
from flowllm import
|
8
|
-
from flowllm.
|
9
|
-
from flowllm.
|
8
|
+
from flowllm.context.flow_context import FlowContext
|
9
|
+
from flowllm.context.service_context import C
|
10
|
+
from flowllm.op.base_llm_op import BaseLLMOp
|
11
|
+
from flowllm.schema.flow_response import FlowResponse
|
10
12
|
from flowllm.schema.message import Message, Role
|
11
13
|
|
12
14
|
|
13
15
|
@C.register_op()
|
14
|
-
class
|
15
|
-
# TODO: test react op
|
16
|
+
class ReactV1Op(BaseLLMOp):
|
16
17
|
file_path: str = __file__
|
17
18
|
|
18
19
|
def execute(self):
|
19
20
|
query: str = self.context.query
|
20
21
|
|
21
22
|
max_steps: int = int(self.op_params.get("max_steps", 10))
|
23
|
+
from flowllm.flow.base_tool_flow import BaseToolFlow
|
24
|
+
from flowllm.flow.gallery import DashscopeSearchToolFlow, CodeToolFlow, TerminateToolFlow
|
25
|
+
|
22
26
|
tools: List[BaseToolFlow] = [DashscopeSearchToolFlow(), CodeToolFlow(), TerminateToolFlow()]
|
23
|
-
|
27
|
+
|
28
|
+
"""
|
29
|
+
NOTE : x.tool_call.name != x.name
|
30
|
+
`x.tool_call.name` is tool's namex.name is flow's name(unique service name)
|
31
|
+
"""
|
32
|
+
tool_dict: Dict[str, BaseToolFlow] = {x.tool_call.name: x for x in tools}
|
33
|
+
for name, tool_call in tool_dict.items():
|
34
|
+
logger.info(f"name={name} "
|
35
|
+
f"tool_call={json.dumps(tool_call.tool_call.simple_input_dump(), ensure_ascii=False)}")
|
36
|
+
|
24
37
|
now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
25
38
|
has_terminate_tool = False
|
26
39
|
|
27
40
|
user_prompt = self.prompt_format(prompt_name="role_prompt",
|
28
41
|
time=now_time,
|
29
|
-
tools=",".join(
|
42
|
+
tools=",".join(list(tool_dict.keys())),
|
30
43
|
query=query)
|
31
44
|
messages: List[Message] = [Message(role=Role.USER, content=user_prompt)]
|
32
45
|
logger.info(f"step.0 user_prompt={user_prompt}")
|
@@ -59,6 +72,7 @@ class ReactOp(BaseLLMOp):
|
|
59
72
|
logger.info(f"submit step={i} tool_calls.name={tool_call.name} argument_dict={tool_call.argument_dict}")
|
60
73
|
|
61
74
|
if tool_call.name not in tool_dict:
|
75
|
+
logger.warning(f"step={i} no tool_call.name={tool_call.name}")
|
62
76
|
continue
|
63
77
|
|
64
78
|
self.submit_task(tool_dict[tool_call.name].__call__, **tool_call.argument_dict)
|
@@ -68,7 +82,10 @@ class ReactOp(BaseLLMOp):
|
|
68
82
|
user_content_list = []
|
69
83
|
for tool_result, tool_call in zip(self.join_task(), assistant_message.tool_calls):
|
70
84
|
logger.info(f"submit step={i} tool_calls.name={tool_call.name} tool_result={tool_result}")
|
71
|
-
|
85
|
+
if isinstance(tool_result, FlowResponse):
|
86
|
+
tool_result = tool_result.answer
|
87
|
+
else:
|
88
|
+
tool_result = str(tool_result)
|
72
89
|
user_content_list.append(f"<tool_response>\n{tool_result}\n</tool_response>")
|
73
90
|
user_content_list.append(self.prompt_format(prompt_name="next_prompt"))
|
74
91
|
assistant_message.tool_calls.clear()
|
@@ -76,8 +93,17 @@ class ReactOp(BaseLLMOp):
|
|
76
93
|
|
77
94
|
else:
|
78
95
|
assistant_message.tool_calls.clear()
|
79
|
-
|
96
|
+
query = self.prompt_format(prompt_name="final_prompt", query=query)
|
97
|
+
messages.append(Message(role=Role.USER, content=query))
|
80
98
|
|
81
99
|
# Store results in context instead of response
|
82
|
-
self.context.messages = messages
|
83
|
-
self.context.answer = messages[-1].content
|
100
|
+
self.context.response.messages = messages
|
101
|
+
self.context.response.answer = messages[-1].content
|
102
|
+
|
103
|
+
|
104
|
+
if __name__ == "__main__":
|
105
|
+
C.set_default_service_config().init_by_service_config()
|
106
|
+
context = FlowContext(query="茅台和五粮现在股价多少?")
|
107
|
+
|
108
|
+
op = ReactV1Op()
|
109
|
+
op(context=context)
|
@@ -26,3 +26,29 @@ final_prompt: |
|
|
26
26
|
# User's Question
|
27
27
|
{query}
|
28
28
|
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
role_prompt_zh: |
|
33
|
+
你是一个有用的助手。
|
34
|
+
当前时间是 {time}。
|
35
|
+
请根据用户的问题,主动选择最合适的工具或工具组合,包括 {tools} 等。
|
36
|
+
请先思考如何将问题分解为子任务,每个子任务应使用哪些工具和参数,最后提供工具调用名称和参数。
|
37
|
+
尝试多次使用相同的工具,但使用不同的参数,从多个角度获取信息。
|
38
|
+
请根据用户问题的语言来确定回复的语言。
|
39
|
+
|
40
|
+
{query}
|
41
|
+
|
42
|
+
next_prompt_zh: |
|
43
|
+
根据当前内容和用户的问题进行思考:当前上下文是否足以回答用户的问题?
|
44
|
+
- 如果当前上下文不足以回答用户的问题,请考虑缺少哪些信息。
|
45
|
+
重新规划并思考如何将缺失的信息分解为子任务。
|
46
|
+
对于每个子任务,确定应使用哪些工具和参数进行查询。
|
47
|
+
请先提供推理过程,然后给出工具调用名称和参数。
|
48
|
+
- 如果当前上下文足以回答用户的问题,请使用 **terminate** 工具。
|
49
|
+
|
50
|
+
final_prompt_zh: |
|
51
|
+
请整合上下文,为用户的问题提供一个完整的答案。
|
52
|
+
|
53
|
+
# 用户的问题
|
54
|
+
{query}
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import datetime
|
2
|
+
import json
|
3
|
+
import time
|
4
|
+
from typing import List, Dict
|
5
|
+
|
6
|
+
from loguru import logger
|
7
|
+
|
8
|
+
from flowllm.context.flow_context import FlowContext
|
9
|
+
from flowllm.context.service_context import C
|
10
|
+
from flowllm.op.base_llm_op import BaseLLMOp
|
11
|
+
from flowllm.schema.flow_response import FlowResponse
|
12
|
+
from flowllm.schema.message import Message, Role
|
13
|
+
|
14
|
+
|
15
|
+
@C.register_op()
|
16
|
+
class ReactV2Op(BaseLLMOp):
|
17
|
+
file_path: str = __file__
|
18
|
+
|
19
|
+
def execute(self):
|
20
|
+
query: str = self.context.query
|
21
|
+
|
22
|
+
max_steps: int = int(self.op_params.get("max_steps", 10))
|
23
|
+
from flowllm.flow.base_tool_flow import BaseToolFlow
|
24
|
+
from flowllm.flow.gallery import DashscopeSearchToolFlow, CodeToolFlow
|
25
|
+
|
26
|
+
tools: List[BaseToolFlow] = [DashscopeSearchToolFlow(), CodeToolFlow()]
|
27
|
+
|
28
|
+
"""
|
29
|
+
NOTE : x.tool_call.name != x.name
|
30
|
+
`x.tool_call.name` is tool's namex.name is flow's name(unique service name)
|
31
|
+
"""
|
32
|
+
tool_dict: Dict[str, BaseToolFlow] = {x.tool_call.name: x for x in tools}
|
33
|
+
for name, tool_call in tool_dict.items():
|
34
|
+
logger.info(f"name={name} "
|
35
|
+
f"tool_call={json.dumps(tool_call.tool_call.simple_input_dump(), ensure_ascii=False)}")
|
36
|
+
|
37
|
+
now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
38
|
+
has_terminate_tool = False
|
39
|
+
|
40
|
+
user_prompt = self.prompt_format(prompt_name="role_prompt",
|
41
|
+
time=now_time,
|
42
|
+
tools=",".join(list(tool_dict.keys())),
|
43
|
+
query=query)
|
44
|
+
messages: List[Message] = [Message(role=Role.USER, content=user_prompt)]
|
45
|
+
logger.info(f"step.0 user_prompt={user_prompt}")
|
46
|
+
|
47
|
+
for i in range(max_steps):
|
48
|
+
assistant_message: Message = self.llm.chat(messages, tools=[x.tool_call for x in tools])
|
49
|
+
messages.append(assistant_message)
|
50
|
+
logger.info(f"assistant.round{i}.reasoning_content={assistant_message.reasoning_content}\n"
|
51
|
+
f"content={assistant_message.content}\n"
|
52
|
+
f"tool.size={len(assistant_message.tool_calls)}")
|
53
|
+
|
54
|
+
if not assistant_message.tool_calls:
|
55
|
+
break
|
56
|
+
|
57
|
+
for j, tool_call in enumerate(assistant_message.tool_calls):
|
58
|
+
logger.info(f"submit step={i} tool_calls.name={tool_call.name} argument_dict={tool_call.argument_dict}")
|
59
|
+
|
60
|
+
if tool_call.name not in tool_dict:
|
61
|
+
logger.warning(f"step={i} no tool_call.name={tool_call.name}")
|
62
|
+
continue
|
63
|
+
|
64
|
+
self.submit_task(tool_dict[tool_call.name].__call__, **tool_call.argument_dict)
|
65
|
+
time.sleep(1)
|
66
|
+
|
67
|
+
for i, (tool_result, tool_call) in enumerate(zip(self.join_task(), assistant_message.tool_calls)):
|
68
|
+
logger.info(f"submit step={i} tool_calls.name={tool_call.name} tool_result={tool_result}")
|
69
|
+
if isinstance(tool_result, FlowResponse):
|
70
|
+
tool_result = tool_result.answer
|
71
|
+
else:
|
72
|
+
tool_result = str(tool_result)
|
73
|
+
tool_message = Message(role=Role.TOOL, content=tool_result, tool_call_id=tool_call.id)
|
74
|
+
messages.append(tool_message)
|
75
|
+
|
76
|
+
# Store results in context instead of response
|
77
|
+
self.context.response.messages = messages
|
78
|
+
self.context.response.answer = messages[-1].content
|
79
|
+
|
80
|
+
|
81
|
+
if __name__ == "__main__":
|
82
|
+
C.set_default_service_config().init_by_service_config()
|
83
|
+
context = FlowContext(query="茅台和五粮现在股价多少?")
|
84
|
+
|
85
|
+
op = ReactV2Op()
|
86
|
+
op(context=context)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
role_prompt: |
|
2
|
+
You are a helpful assistant.
|
3
|
+
The current time is {time}.
|
4
|
+
Please proactively choose the most suitable tool or combination of tools based on the user's question, including {tools} etc.
|
5
|
+
Please first think about how to break down the problem into subtasks, what tools and parameters should be used for each subtask, and finally provide the tool call name and parameters.
|
6
|
+
Try calling the same tool multiple times with different parameters to obtain information from various perspectives.
|
7
|
+
Please determine the response language based on the language of the user's question.
|
8
|
+
|
9
|
+
{query}
|
10
|
+
|
11
|
+
next_prompt: |
|
12
|
+
Think based on the current content and the user's question: Is the current context sufficient to answer the user's question?
|
13
|
+
- If the current context is not sufficient to answer the user's question, consider what information is missing.
|
14
|
+
Re-plan and think about how to break down the missing information into subtasks.
|
15
|
+
For each subtask, determine what tools and parameters should be used for the query.
|
16
|
+
Please first provide the reasoning process, then give the tool call name and parameters.
|
17
|
+
- If the current context is sufficient to answer the user's question, please integrate the context and provide a complete answer to the user's question.
|
18
|
+
|
19
|
+
role_prompt_zh: |
|
20
|
+
你是一个有用的助手。
|
21
|
+
当前时间是 {time}。
|
22
|
+
请根据用户的问题,主动选择最合适的工具或工具组合,包括 {tools} 等。
|
23
|
+
请先思考如何将问题分解为子任务,每个子任务应使用哪些工具和参数,最后提供工具调用名称和参数。
|
24
|
+
尝试多次使用相同的工具,但使用不同的参数,从多个角度获取信息。
|
25
|
+
请根据用户问题的语言来确定回复的语言。
|
26
|
+
|
27
|
+
{query}
|
28
|
+
|
29
|
+
next_prompt_zh: |
|
30
|
+
根据当前内容和用户的问题进行思考:当前上下文是否足以回答用户的问题?
|
31
|
+
- 如果当前上下文不足以回答用户的问题,请考虑缺少哪些信息。
|
32
|
+
重新规划并思考如何将缺失的信息分解为子任务。
|
33
|
+
对于每个子任务,确定应使用哪些工具和参数进行查询。
|
34
|
+
请先提供推理过程,然后给出工具调用名称和参数。
|
35
|
+
- 如果当前上下文足以回答用户的问题,请整合上下文,为用户的问题提供一个完整的答案。
|
flowllm/op/base_llm_op.py
CHANGED
@@ -23,8 +23,9 @@ class BaseLLMOp(BaseOp, ABC):
|
|
23
23
|
super().__init__(**kwargs)
|
24
24
|
|
25
25
|
self.language: str = language or C.language
|
26
|
-
|
27
|
-
|
26
|
+
default_prompt_path = self.file_path.replace("op.py", "prompt.yaml")
|
27
|
+
self.prompt_path: Path = Path(prompt_path) if prompt_path else default_prompt_path
|
28
|
+
|
28
29
|
self._llm: BaseLLM | str = llm
|
29
30
|
self._embedding_model: BaseEmbeddingModel | str = embedding_model
|
30
31
|
self._vector_store: BaseVectorStore | str = vector_store
|
flowllm/op/base_op.py
CHANGED
@@ -16,11 +16,13 @@ class BaseOp(ABC):
|
|
16
16
|
def __init__(self,
|
17
17
|
name: str = "",
|
18
18
|
raise_exception: bool = True,
|
19
|
+
enable_multithread: bool = True,
|
19
20
|
**kwargs):
|
20
21
|
super().__init__()
|
21
22
|
|
22
23
|
self.name: str = name or camel_to_snake(self.__class__.__name__)
|
23
24
|
self.raise_exception: bool = raise_exception
|
25
|
+
self.enable_multithread: bool = enable_multithread
|
24
26
|
self.op_params: dict = kwargs
|
25
27
|
|
26
28
|
self.task_list: List[Future] = []
|
@@ -48,19 +50,34 @@ class BaseOp(ABC):
|
|
48
50
|
return self.context.response if self.context else None
|
49
51
|
|
50
52
|
def submit_task(self, fn, *args, **kwargs):
|
51
|
-
|
52
|
-
|
53
|
+
if self.enable_multithread:
|
54
|
+
task = C.thread_pool.submit(fn, *args, **kwargs)
|
55
|
+
self.task_list.append(task)
|
56
|
+
|
57
|
+
else:
|
58
|
+
result = fn(*args, **kwargs)
|
59
|
+
if result:
|
60
|
+
if isinstance(result, list):
|
61
|
+
result.extend(result)
|
62
|
+
else:
|
63
|
+
result.append(result)
|
64
|
+
|
53
65
|
return self
|
54
66
|
|
55
67
|
def join_task(self, task_desc: str = None) -> list:
|
56
68
|
result = []
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
if
|
61
|
-
|
62
|
-
|
63
|
-
|
69
|
+
if self.enable_multithread:
|
70
|
+
for task in tqdm(self.task_list, desc=task_desc or self.name):
|
71
|
+
t_result = task.result()
|
72
|
+
if t_result:
|
73
|
+
if isinstance(t_result, list):
|
74
|
+
result.extend(t_result)
|
75
|
+
else:
|
76
|
+
result.append(t_result)
|
77
|
+
|
78
|
+
else:
|
79
|
+
result.extend(self.task_list)
|
80
|
+
|
64
81
|
self.task_list.clear()
|
65
82
|
return result
|
66
83
|
|
@@ -40,8 +40,15 @@ class DashscopeDeepResearchOp(BaseLLMOp):
|
|
40
40
|
self.return_only_content = return_only_content
|
41
41
|
|
42
42
|
# Ensure API key is available
|
43
|
-
self.api_key = os.
|
44
|
-
self.
|
43
|
+
self.api_key = os.environ["FLOW_DASHSCOPE_API_KEY"]
|
44
|
+
self.cache_path: str = cache_path
|
45
|
+
self._cache: DataCache | None = None
|
46
|
+
|
47
|
+
@property
|
48
|
+
def cache(self):
|
49
|
+
if self.enable_cache and self._cache is None:
|
50
|
+
self._cache = DataCache(self.cache_path)
|
51
|
+
return self._cache
|
45
52
|
|
46
53
|
def process_responses(self, responses, step_name):
|
47
54
|
"""Process streaming responses from the deep research model"""
|
@@ -45,8 +45,15 @@ class DashscopeSearchOp(BaseLLMOp):
|
|
45
45
|
self.enable_role_prompt = enable_role_prompt
|
46
46
|
|
47
47
|
# Ensure API key is available
|
48
|
-
self.api_key = os.
|
49
|
-
self.
|
48
|
+
self.api_key = os.environ["FLOW_DASHSCOPE_API_KEY"]
|
49
|
+
self.cache_path: str = cache_path
|
50
|
+
self._cache: DataCache | None = None
|
51
|
+
|
52
|
+
@property
|
53
|
+
def cache(self):
|
54
|
+
if self.enable_cache and self._cache is None:
|
55
|
+
self._cache = DataCache(self.cache_path)
|
56
|
+
return self._cache
|
50
57
|
|
51
58
|
@staticmethod
|
52
59
|
def format_search_results(search_results: List[Dict[str, Any]]) -> str:
|
@@ -16,8 +16,8 @@ from flowllm.storage.cache.data_cache import DataCache
|
|
16
16
|
class TavilySearchOp(BaseOp):
|
17
17
|
def __init__(self,
|
18
18
|
enable_print: bool = True,
|
19
|
-
enable_cache: bool =
|
20
|
-
cache_path: str = "./
|
19
|
+
enable_cache: bool = True,
|
20
|
+
cache_path: str = "./tavily_search_cache",
|
21
21
|
cache_expire_hours: float = 0.1,
|
22
22
|
topic: Literal["general", "news", "finance"] = "general",
|
23
23
|
max_retries: int = 3,
|
@@ -33,8 +33,15 @@ class TavilySearchOp(BaseOp):
|
|
33
33
|
self.return_only_content = return_only_content
|
34
34
|
|
35
35
|
# Initialize DataCache if caching is enabled
|
36
|
-
self.cache = DataCache(cache_path) if self.enable_cache else None
|
37
36
|
self._client = TavilyClient(api_key=os.getenv("FLOW_TAVILY_API_KEY", ""))
|
37
|
+
self.cache_path: str = cache_path
|
38
|
+
self._cache: DataCache | None = None
|
39
|
+
|
40
|
+
@property
|
41
|
+
def cache(self):
|
42
|
+
if self.enable_cache and self._cache is None:
|
43
|
+
self._cache = DataCache(self.cache_path)
|
44
|
+
return self._cache
|
38
45
|
|
39
46
|
def post_process(self, response):
|
40
47
|
if self.enable_print:
|
flowllm/schema/message.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import datetime
|
1
2
|
from typing import List
|
2
3
|
|
3
4
|
from pydantic import BaseModel, Field
|
@@ -12,6 +13,7 @@ class Message(BaseModel):
|
|
12
13
|
reasoning_content: str = Field(default="")
|
13
14
|
tool_calls: List[ToolCall] = Field(default_factory=list)
|
14
15
|
tool_call_id: str = Field(default="")
|
16
|
+
time_created: str = Field(default_factory=lambda: datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
15
17
|
metadata: dict = Field(default_factory=dict)
|
16
18
|
|
17
19
|
def simple_dump(self, add_reason_content: bool = True) -> dict:
|
flowllm/schema/tool_call.py
CHANGED
@@ -58,12 +58,16 @@ class ToolCall(BaseModel):
|
|
58
58
|
type: str = Field(default="function")
|
59
59
|
name: str = Field(default="")
|
60
60
|
|
61
|
-
arguments:
|
61
|
+
arguments: str = Field(default="", description="tool execution arguments")
|
62
62
|
|
63
63
|
description: str = Field(default="")
|
64
64
|
input_schema: Dict[str, ParamAttrs] = Field(default_factory=dict)
|
65
65
|
output_schema: Dict[str, ParamAttrs] = Field(default_factory=dict)
|
66
66
|
|
67
|
+
@property
|
68
|
+
def argument_dict(self) -> dict:
|
69
|
+
return json.loads(self.arguments)
|
70
|
+
|
67
71
|
def simple_input_dump(self, version: str = "v1") -> dict:
|
68
72
|
if version == "v1":
|
69
73
|
required_list = [name for name, tool_param in self.input_schema.items() if tool_param.required]
|
@@ -91,7 +95,7 @@ class ToolCall(BaseModel):
|
|
91
95
|
"index": self.index,
|
92
96
|
"id": self.id,
|
93
97
|
self.type: {
|
94
|
-
"arguments":
|
98
|
+
"arguments": self.arguments,
|
95
99
|
"name": self.name
|
96
100
|
},
|
97
101
|
"type": self.type,
|
@@ -111,7 +115,7 @@ class ToolCall(BaseModel):
|
|
111
115
|
if name:
|
112
116
|
self.name = name
|
113
117
|
if arguments:
|
114
|
-
self.arguments =
|
118
|
+
self.arguments = arguments
|
115
119
|
else:
|
116
120
|
raise NotImplementedError(f"version {version} not supported")
|
117
121
|
|
flowllm/service/http_service.py
CHANGED
@@ -65,8 +65,8 @@ class HttpService(BaseService):
|
|
65
65
|
|
66
66
|
return await loop.run_in_executor(executor=C.thread_pool, func=list_tool_flows) # noqa
|
67
67
|
|
68
|
-
endpoint_path = "
|
69
|
-
self.app.get(endpoint_path, response_model=list)(execute_endpoint)
|
68
|
+
endpoint_path = "list"
|
69
|
+
self.app.get("/" + endpoint_path, response_model=list)(execute_endpoint)
|
70
70
|
logger.info(f"integrate endpoint={endpoint_path}")
|
71
71
|
|
72
72
|
def __call__(self):
|
@@ -24,6 +24,9 @@ class BaseVectorStore(BaseModel, ABC):
|
|
24
24
|
def _iter_workspace_nodes(self, workspace_id: str, **kwargs) -> Iterable[VectorNode]:
|
25
25
|
raise NotImplementedError
|
26
26
|
|
27
|
+
def iter_workspace_nodes(self, workspace_id: str, **kwargs) -> Iterable[VectorNode]:
|
28
|
+
return self._iter_workspace_nodes(workspace_id, **kwargs)
|
29
|
+
|
27
30
|
def dump_workspace(self, workspace_id: str, path: str | Path = "", callback_fn=None, **kwargs):
|
28
31
|
raise NotImplementedError
|
29
32
|
|
@@ -62,7 +62,7 @@ class EsVectorStore(LocalVectorStore):
|
|
62
62
|
node.workspace_id = workspace_id
|
63
63
|
node.unique_id = doc["_id"]
|
64
64
|
if "_score" in doc:
|
65
|
-
node.metadata["
|
65
|
+
node.metadata["score"] = doc["_score"] - 1
|
66
66
|
return node
|
67
67
|
|
68
68
|
def add_term_filter(self, key: str, value):
|
@@ -111,7 +111,7 @@ class EsVectorStore(LocalVectorStore):
|
|
111
111
|
self.retrieve_filters.clear()
|
112
112
|
return nodes
|
113
113
|
|
114
|
-
def insert(self, nodes: VectorNode | List[VectorNode], workspace_id: str, refresh: bool =
|
114
|
+
def insert(self, nodes: VectorNode | List[VectorNode], workspace_id: str, refresh: bool = True, **kwargs):
|
115
115
|
if not self.exist_workspace(workspace_id=workspace_id):
|
116
116
|
self.create_workspace(workspace_id=workspace_id)
|
117
117
|
|
@@ -140,7 +140,7 @@ class EsVectorStore(LocalVectorStore):
|
|
140
140
|
if refresh:
|
141
141
|
self.refresh(workspace_id=workspace_id)
|
142
142
|
|
143
|
-
def delete(self, node_ids: str | List[str], workspace_id: str, refresh: bool =
|
143
|
+
def delete(self, node_ids: str | List[str], workspace_id: str, refresh: bool = True, **kwargs):
|
144
144
|
if not self.exist_workspace(workspace_id=workspace_id):
|
145
145
|
logger.warning(f"workspace_id={workspace_id} is not exists!")
|
146
146
|
return
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
from datetime import datetime
|
4
|
+
|
5
|
+
|
6
|
+
def init_logger():
|
7
|
+
from loguru import logger
|
8
|
+
logger.remove()
|
9
|
+
|
10
|
+
log_dir = "logs"
|
11
|
+
os.makedirs(log_dir, exist_ok=True)
|
12
|
+
|
13
|
+
current_ts = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
14
|
+
|
15
|
+
log_filename = f"{current_ts}.log"
|
16
|
+
log_filepath = os.path.join(log_dir, log_filename)
|
17
|
+
|
18
|
+
logger.add(log_filepath,
|
19
|
+
level="DEBUG",
|
20
|
+
rotation="00:00",
|
21
|
+
retention="7 days",
|
22
|
+
compression="zip",
|
23
|
+
encoding="utf-8")
|
24
|
+
|
25
|
+
logger.add(sink=sys.stdout,
|
26
|
+
level="INFO",
|
27
|
+
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
|
28
|
+
colorize=True)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
flowllm/__init__.py,sha256=
|
1
|
+
flowllm/__init__.py,sha256=lpsBaF4a0u2xSFdGCN8L-CFLuyGxLdR53PjZF4G2dOM,503
|
2
2
|
flowllm/app.py,sha256=oo_7c1sXeWOEkdIL40b_Yv-vkvu6YWhs3w49SojE4bs,238
|
3
3
|
flowllm/client/__init__.py,sha256=ruBU6hBC7LWoVg5oNdZBTqi3MhNUhkCYAHhPj-UJKEA,815
|
4
4
|
flowllm/client/async_http_client.py,sha256=w3YUsCTlART3HvAIpf30ZIX4m7L7k9f9iZejkNBq_h8,3026
|
@@ -14,7 +14,7 @@ flowllm/context/base_context.py,sha256=NTP6EzfIlcjvwT5-wYDL5_gDoH88rAxTqsknR97tx
|
|
14
14
|
flowllm/context/flow_context.py,sha256=-r96PgXC7BXVjA6bbUKw_cI5r3VRgQJ0AqG3iES4xSw,463
|
15
15
|
flowllm/context/prompt_handler.py,sha256=LbMJDwrzz8HF7HVDyphVSWI1X4QHMebJqLP4XeXkXOE,2667
|
16
16
|
flowllm/context/registry.py,sha256=zJf8SYi8ziFTdf2EG9Ut2_3sxEffchrl81W-VbcoEns,1110
|
17
|
-
flowllm/context/service_context.py,sha256=
|
17
|
+
flowllm/context/service_context.py,sha256=iH1h6mJxYxcU-LkNN5jurVLIqfaPs7sroR6JRo87Trg,5858
|
18
18
|
flowllm/embedding_model/__init__.py,sha256=jHxnI2xySqYcu7Y2wxmlmpIyYeKH_4PuNCBNvouXhEE,78
|
19
19
|
flowllm/embedding_model/base_embedding_model.py,sha256=oIySUu6_ROEXw13jtKYUtnL0bgBQdHtNZqnPPxatG9I,8021
|
20
20
|
flowllm/embedding_model/openai_compatible_embedding_model.py,sha256=N873ZlMdoB6iRu-oXkXlNNkIdH6F4hFN3ND7EA0FcwA,5490
|
@@ -23,7 +23,7 @@ flowllm/enumeration/chunk_enum.py,sha256=EYB0a84qtrph5H7h_m05Qeo5B00B3xnSOt9KBb5
|
|
23
23
|
flowllm/enumeration/http_enum.py,sha256=ddIYeVz2J8CInzEkhWbz1rPe0qh2FVfryNNE1uc1ioM,141
|
24
24
|
flowllm/enumeration/role.py,sha256=SFMGXmwYFndGIwbr9GxS3OIoHIZ_nO23DeRnqpV4U3g,133
|
25
25
|
flowllm/flow/__init__.py,sha256=m2SCRH8CbDGsYXaUn99FGD9bz5KoDpLAcFu1GXu3GCo,22
|
26
|
-
flowllm/flow/base_flow.py,sha256=
|
26
|
+
flowllm/flow/base_flow.py,sha256=DAZfIP1G5ksTDoS9rkWYom8z9-9h6XOMd8XARQJByD0,2548
|
27
27
|
flowllm/flow/base_tool_flow.py,sha256=eC-V9kafecsXJixqXGfmD1DF70tA8ClM2f4rnW2K1vU,368
|
28
28
|
flowllm/flow/gallery/__init__.py,sha256=fT1aFrcw-QvFkEnPkOXHMZNK9IDapH0U_iEfwRbq7oI,391
|
29
29
|
flowllm/flow/gallery/cmd_flow.py,sha256=nqwMufrJWsJLmNaIVwJ6M11Hnxfpl1FvW07EC95qzN0,337
|
@@ -31,24 +31,26 @@ flowllm/flow/gallery/code_tool_flow.py,sha256=s-97BHplWO4Me4eTPNDltZL7XcGIAsz8IB
|
|
31
31
|
flowllm/flow/gallery/dashscope_search_tool_flow.py,sha256=RxyWNQ-h0tt7236H7fAURqDEKNvccI5jGQA07TAKbLg,1153
|
32
32
|
flowllm/flow/gallery/deepsearch_tool_flow.py,sha256=_3JUiNivDGZxo-i1zHtX3MPMuqJSZXEZ2A2Mm_IUIY8,1426
|
33
33
|
flowllm/flow/gallery/expression_tool_flow.py,sha256=U0s9znCPSFwuqc7SalidjDGI-0kr9KGK3fWEQCN_q58,665
|
34
|
-
flowllm/flow/gallery/mock_tool_flow.py,sha256=
|
34
|
+
flowllm/flow/gallery/mock_tool_flow.py,sha256=BQ4aulE0qurL3ty9_1Diwbhw65z2HmVdP_iS-sxJsy4,2250
|
35
35
|
flowllm/flow/gallery/tavily_search_tool_flow.py,sha256=DJeHx-ry4cAOaVsRy28Kob3ecwnq41bsAo0gTmokArE,1046
|
36
|
-
flowllm/flow/gallery/terminate_tool_flow.py,sha256=
|
36
|
+
flowllm/flow/gallery/terminate_tool_flow.py,sha256=dm63zg1vjuieR0GHIltyIcaZAdRkYgyUAS7toQRxQts,1100
|
37
37
|
flowllm/flow/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
38
|
flowllm/flow/parser/expression_parser.py,sha256=E8ZGmrdFpOgUQBtXxtVXb-BD7RUtfLkcWsIQBKTqdcA,5990
|
39
39
|
flowllm/llm/__init__.py,sha256=c2akU1k4IVT6PoW3FdKlFmQNZj7MVCzV_VTUw5VpDrc,99
|
40
40
|
flowllm/llm/base_llm.py,sha256=6YDlb9B9q4zQGQjFLVKNdd7JoELws9IzHebs2nDfUzc,9554
|
41
|
-
flowllm/llm/litellm_llm.py,sha256=
|
41
|
+
flowllm/llm/litellm_llm.py,sha256=fZpbThfRRyOBPASdZfGHUr_twwzgombbEEhWDQtuzus,19422
|
42
42
|
flowllm/llm/openai_compatible_llm.py,sha256=MKbe4-p4NkCBCCkrty0mFsBTRpXctI-7rz0-2kzvNQo,18534
|
43
|
-
flowllm/op/__init__.py,sha256=
|
44
|
-
flowllm/op/base_llm_op.py,sha256=
|
45
|
-
flowllm/op/base_op.py,sha256=
|
43
|
+
flowllm/op/__init__.py,sha256=AQIt-aEJ_TDQZYKqDNnnG9rQNLw-siXLuv69wPGN1tY,221
|
44
|
+
flowllm/op/base_llm_op.py,sha256=mzRKgROambE1xI4JSwNrCLdkN6y-PemCGzZERqVpJr8,2682
|
45
|
+
flowllm/op/base_op.py,sha256=Fo1k-FbuMm_kFu_thdfclj5z3EhBZeu_7Zgnv18--Hg,4653
|
46
46
|
flowllm/op/base_ray_op.py,sha256=-nRbad0pQ4qkZaDbonBDf6qh_dzktzOTCc-XkiLiIT4,11238
|
47
47
|
flowllm/op/parallel_op.py,sha256=Q66uB-uINsBj_m6NH140kiQPN1o9aw-wkc_5y74EaRY,551
|
48
48
|
flowllm/op/sequential_op.py,sha256=F8YTNCvPL0WsC_6Al9utnCErGnnnsEpaw4MVeUX3Skk,477
|
49
|
-
flowllm/op/agent/__init__.py,sha256=
|
50
|
-
flowllm/op/agent/
|
51
|
-
flowllm/op/agent/
|
49
|
+
flowllm/op/agent/__init__.py,sha256=BQarnmiPI9ydGIOkRgDrr6X7ZdNw4o_iJo2Ne0i1Bd8,35
|
50
|
+
flowllm/op/agent/react_v1_op.py,sha256=sobCuTLlPpWtK1H2YOKpqkRLuxKMN2YQFPvY-k4ltBI,4711
|
51
|
+
flowllm/op/agent/react_v1_prompt.yaml,sha256=q4PC_ygoByzOV0wJDZnL2feLbp-nVNzkT6vN8YDx8hY,2695
|
52
|
+
flowllm/op/agent/react_v2_op.py,sha256=L01IVaPyRJD-kxgUiJMf0EoLMXMfdV06NfCGUSXzt4o,3627
|
53
|
+
flowllm/op/agent/react_v2_prompt.yaml,sha256=UnBvR_2ph7AG-HNDkn-SJvZiym-UcbcizKdc9w9NImg,2344
|
52
54
|
flowllm/op/akshare/__init__.py,sha256=PaCPzBv-csRgmtmBjoYqxvOgAB3Vp8EeSGP3rGw6rc8,178
|
53
55
|
flowllm/op/akshare/get_ak_a_code_op.py,sha256=Pa766YbR_SPLHbQZQpW0UBBUBcXqigeEj10ypp3V3K4,3855
|
54
56
|
flowllm/op/akshare/get_ak_a_code_prompt.yaml,sha256=NwGJygecUwspQvrg98GdMpcmQESpZ2Kf5YprhM2PyZU,608
|
@@ -59,41 +61,42 @@ flowllm/op/gallery/__init__.py,sha256=5S2pzO65wOpE7PnirS6FiBN1uEm49Y40PZiW9EnGMn
|
|
59
61
|
flowllm/op/gallery/mock_op.py,sha256=3GfqtOQm87A9TmZTD5Z4jcAxqPbtvmNQA7qTFcp897E,664
|
60
62
|
flowllm/op/gallery/terminate_op.py,sha256=dHiXONYDXkhePsmzAMa8FRktodZroB_G-UXApTNME3w,866
|
61
63
|
flowllm/op/search/__init__.py,sha256=iCxX7lBOWmgBM-xiLUN3SAB3LtYiS4Dk9ZEew-vlIBM,160
|
62
|
-
flowllm/op/search/dashscope_deep_research_op.py,sha256=
|
63
|
-
flowllm/op/search/dashscope_search_op.py,sha256=
|
64
|
+
flowllm/op/search/dashscope_deep_research_op.py,sha256=eUjvcZ-QFcYHi5Ya4fodfBf9KvtzApTK4p-Ij_73MWA,11682
|
65
|
+
flowllm/op/search/dashscope_search_op.py,sha256=AXGsTJ5KCBPwZxr_ZtezBpnY8MdBuOiZztRXrJH_oyo,7115
|
64
66
|
flowllm/op/search/dashscope_search_prompt.yaml,sha256=NPsS3QCo8xlRpWw7fyMpuYBeOXSAtXscwGO-cVgUNFw,355
|
65
|
-
flowllm/op/search/tavily_search_op.py,sha256=
|
67
|
+
flowllm/op/search/tavily_search_op.py,sha256=Well79n86Q-wr27kVhffKQVHeuG3Gc5PwT0aTlH7xe0,3999
|
66
68
|
flowllm/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
67
69
|
flowllm/schema/flow_request.py,sha256=jaOgEJ7XRWNgS_QTCBOOsa6hKtdgqnXVC7S4Vi6lMBg,338
|
68
70
|
flowllm/schema/flow_response.py,sha256=BusrfkJ8OCGk9Tp1KCWVSt33L2t_pYpn9QRqS0bjDcw,323
|
69
|
-
flowllm/schema/message.py,sha256=
|
71
|
+
flowllm/schema/message.py,sha256=MvTKhUX5yUY9mcP9vEFRZ4RJMObhUPQ3iQjOC_OpTvU,1345
|
70
72
|
flowllm/schema/service_config.py,sha256=Gaw-EKuwc7kmdR1yaVN04qruaESeUSguivK4JUfCPBQ,2324
|
71
|
-
flowllm/schema/tool_call.py,sha256=
|
73
|
+
flowllm/schema/tool_call.py,sha256=VTRSwcL7W98my9lX-tAXgTfcXz7ZirXdTaCyyod2ZKs,3998
|
72
74
|
flowllm/schema/vector_node.py,sha256=Urs9EyzzjuQVYPCB_Pfp0iK2npWWCJSXdT6uDLdT05w,362
|
73
75
|
flowllm/service/__init__.py,sha256=Jr-f0i1yCIoM4XZ3SbOcqMU81Np3YgNZs6z36YfUpzQ,110
|
74
76
|
flowllm/service/base_service.py,sha256=6KJnIVkaIBNHwtQY83LmEMoTiMK5qI0ZtNMmIVjEZ5E,2335
|
75
77
|
flowllm/service/cmd_service.py,sha256=TfN2TLVNR75jUcAgjeOkxsA7ORCkERvRkuCE3Get7f0,464
|
76
|
-
flowllm/service/http_service.py,sha256=
|
78
|
+
flowllm/service/http_service.py,sha256=xh6rnXJ7PhmCAvlQFUPDMLCS7CgrQXGoFbxuKmc1KgU,2812
|
77
79
|
flowllm/service/mcp_service.py,sha256=DR116-EeFBI_Sqbxu0X2NJ1e4cD8-T6kTYzPEPYsCuY,1889
|
78
80
|
flowllm/storage/__init__.py,sha256=wlGDDqp6nM4TLoEAXtSglgB0-K2YHAq_DNnsHTBQj8s,41
|
79
81
|
flowllm/storage/cache/__init__.py,sha256=KyLfUg3gJ4SvHMRagtZDL8cp5s5SRsN9H-_y4uRf2II,34
|
80
82
|
flowllm/storage/cache/cache_data_handler.py,sha256=fNnVwKOTOL3fZfukIN2gy3txlxiwr3CR9t3tVnIusvw,2700
|
81
83
|
flowllm/storage/cache/data_cache.py,sha256=cVz20JUkGgXzB5YgZiyeiBYpA0nRFyBtxhgVVQkFeA4,12144
|
82
84
|
flowllm/storage/vector_store/__init__.py,sha256=0DH2mkNiQ_cB5yPzm2Xc-7qsFHz1ytMkGUptWGZkyuU,143
|
83
|
-
flowllm/storage/vector_store/base_vector_store.py,sha256=
|
85
|
+
flowllm/storage/vector_store/base_vector_store.py,sha256=SmiixZVZu_VYTsUTFcJFz5GsC29FesjNJxmhdH1F3f8,1791
|
84
86
|
flowllm/storage/vector_store/chroma_vector_store.py,sha256=BHcfhMBBDaoQOywfhYgp87v6OjTf0ePyTI2h-MWQywc,7067
|
85
|
-
flowllm/storage/vector_store/es_vector_store.py,sha256=
|
87
|
+
flowllm/storage/vector_store/es_vector_store.py,sha256=nO8EFNA7sixocsFxeW1QV4GZryqCQWhpMCYyNLRimXo,8449
|
86
88
|
flowllm/storage/vector_store/local_vector_store.py,sha256=p8xg2cmv17bm1UYXZBhLMAGulOE8v70Iw4oTM0Ls61s,10396
|
87
89
|
flowllm/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
90
|
flowllm/utils/common_utils.py,sha256=v9vTK_FrOsyXNZN2-CRJ6zLrCqaSX0-LNpt6IFt6sNg,1232
|
89
91
|
flowllm/utils/fetch_url.py,sha256=pOYiliL4kTGQKERCHrFhammBsbv9XzSvVyBQDMgXKEY,4404
|
90
92
|
flowllm/utils/llm_utils.py,sha256=ywhf1LGe2aKEaL5PyOpoOAbiekrQVOcpxUJ4ARPioQQ,1121
|
93
|
+
flowllm/utils/logger_utils.py,sha256=cBgBKO_oQlN0O19AR0tMxmMo1TTaDdjPI3_g2Xy8Csw,703
|
91
94
|
flowllm/utils/ridge_v2.py,sha256=XIn6nu4jUV7_QUCeyhSEhm-4ltueaS7JdbDQmSQFnRE,1802
|
92
95
|
flowllm/utils/singleton.py,sha256=No3otyPDRHu6wQuFRC-w28MkbommVFTLd7H4mT6-Zos,213
|
93
96
|
flowllm/utils/timer.py,sha256=8aj3dIYOyxNDNdlcitezdepxEptqkx69aw6JNFWsr30,1492
|
94
|
-
flowllm-0.1.
|
95
|
-
flowllm-0.1.
|
96
|
-
flowllm-0.1.
|
97
|
-
flowllm-0.1.
|
98
|
-
flowllm-0.1.
|
99
|
-
flowllm-0.1.
|
97
|
+
flowllm-0.1.3.dist-info/licenses/LICENSE,sha256=kFfPsL7YvEW4jPATpyvUPdtEgftLK53zQrVYJ0eBASY,11337
|
98
|
+
flowllm-0.1.3.dist-info/METADATA,sha256=lphM37crlffgPhkeOFzPQsOHd-nKN4tB5JyJKQSXmBg,14756
|
99
|
+
flowllm-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
100
|
+
flowllm-0.1.3.dist-info/entry_points.txt,sha256=PcKC61HCKtF4ONb4HnrIY6J2JeV1bsi_l0O2m99A2Wg,45
|
101
|
+
flowllm-0.1.3.dist-info/top_level.txt,sha256=a2tZBwbrnw4uiydMI5kAEGz-cxG25rf6v0QM1sYIrjs,8
|
102
|
+
flowllm-0.1.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|