tina-python 0.2.0__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.
- tina/Agent.py +353 -0
- tina/Environment.py +33 -0
- tina/LLM/DeepSeek.py +8 -0
- tina/LLM/Kimi.py +141 -0
- tina/LLM/Qwen.py +8 -0
- tina/LLM/__init__.py +0 -0
- tina/LLM/api.py +145 -0
- tina/LLM/llama.py +306 -0
- tina/RAG/Embedding/QwenEmbeddings.py +56 -0
- tina/RAG/Embedding/__init__.py +0 -0
- tina/RAG/Embedding/docToVec.py +30 -0
- tina/RAG/Embedding/embedding.py +27 -0
- tina/RAG/__init__.py +0 -0
- tina/RAG/processFiles.py +135 -0
- tina/RAG/query/__init__.py +0 -0
- tina/RAG/query/query.py +39 -0
- tina/RAG/textSegments.py +117 -0
- tina/RAG/utils.py +55 -0
- tina/__init__.py +1 -0
- tina/core/__init__.py +0 -0
- tina/core/executor.py +117 -0
- tina/core/logging.py +6 -0
- tina/core/manage.py +84 -0
- tina/core/memory.py +219 -0
- tina/core/parser.py +42 -0
- tina/core/prompt.py +34 -0
- tina/core/tools.py +310 -0
- tina/extend/__init__.py +3 -0
- tina/extend/multi-sourceInput.py +0 -0
- tina/tina.py +211 -0
- tina/tools/NULLTools.py +3 -0
- tina/tools/QwenDocToVec.py +41 -0
- tina/tools/__init__.py +1 -0
- tina/tools/codeMarker.py +63 -0
- tina/tools/readLoogText.py +20 -0
- tina/tools/search.py +0 -0
- tina/tools/systemTools.py +51 -0
- tina_python-0.2.0.dist-info/METADATA +358 -0
- tina_python-0.2.0.dist-info/RECORD +41 -0
- tina_python-0.2.0.dist-info/WHEEL +5 -0
- tina_python-0.2.0.dist-info/top_level.txt +1 -0
tina/LLM/api.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from typing import Union, Generator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseAPI():
|
|
8
|
+
API_ENV_VAR_NAME = "API_KEY" # 默认的API key环境变量名称
|
|
9
|
+
BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1" # 默认的base_url
|
|
10
|
+
|
|
11
|
+
def __init__(self, api_key: str = None, model: str = "qwen-plus", base_url: str = None):
|
|
12
|
+
if api_key is None:
|
|
13
|
+
try:
|
|
14
|
+
self.api_key = os.environ.get(self.API_ENV_VAR_NAME)
|
|
15
|
+
except KeyError:
|
|
16
|
+
print(f"API key并没有在环境变量‘{self.API_ENV_VAR_NAME}’中找到,要么请你设置一下,要么输入api_key参数")
|
|
17
|
+
else:
|
|
18
|
+
print(f"我们建议你在环境变量中设置{self.API_ENV_VAR_NAME},不要输入api_key参数哦")
|
|
19
|
+
self.api_key = api_key
|
|
20
|
+
|
|
21
|
+
self.base_url = base_url if base_url else self.BASE_URL
|
|
22
|
+
self._call = "API"
|
|
23
|
+
self.context_length = 32757
|
|
24
|
+
self.model = model
|
|
25
|
+
self.token = 0
|
|
26
|
+
|
|
27
|
+
def predict(self,
|
|
28
|
+
input_text: str = None,
|
|
29
|
+
sys_prompt: str = '你的工作非常的出色!',
|
|
30
|
+
messages: list = None,
|
|
31
|
+
temperature: float = 0.3,
|
|
32
|
+
top_p: float = 0.9,
|
|
33
|
+
stream: bool = False,
|
|
34
|
+
format:str = "text",
|
|
35
|
+
json_format:str = '{}',
|
|
36
|
+
tools: list = None) -> Union[dict, Generator[dict, None, None]]:
|
|
37
|
+
if messages is None:
|
|
38
|
+
messages = []
|
|
39
|
+
messages.append({"role": "system", "content": sys_prompt})
|
|
40
|
+
# 处理消息列表
|
|
41
|
+
if input_text:
|
|
42
|
+
messages.append({"role": "user", "content": input_text})
|
|
43
|
+
|
|
44
|
+
# 请求参数
|
|
45
|
+
format_dict = {
|
|
46
|
+
'text': 'text',
|
|
47
|
+
'json': 'json_object'
|
|
48
|
+
}
|
|
49
|
+
format = format_dict[format]
|
|
50
|
+
payload = {
|
|
51
|
+
"model": self.model,
|
|
52
|
+
"messages": messages,
|
|
53
|
+
"temperature": temperature,
|
|
54
|
+
"top_p": top_p,
|
|
55
|
+
"stream": stream,
|
|
56
|
+
"tools": tools
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
headers = {
|
|
60
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
61
|
+
"Content-Type": "application/json"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# **非流式请求**
|
|
65
|
+
if not stream:
|
|
66
|
+
response = httpx.post(f"{self.base_url}/chat/completions", json=payload, headers=headers, timeout=30)
|
|
67
|
+
response_data = response.json()
|
|
68
|
+
self.token += response_data.get("usage", {}).get("total_tokens", 0)
|
|
69
|
+
|
|
70
|
+
result = {"role": "assistant", "content": response_data["choices"][0]["message"]["content"]}
|
|
71
|
+
|
|
72
|
+
# 如果包含工具调用,添加 tool_calls
|
|
73
|
+
tool_calls = response_data["choices"][0]["message"].get("tool_calls")
|
|
74
|
+
if tool_calls:
|
|
75
|
+
result["tool_calls"] = tool_calls
|
|
76
|
+
|
|
77
|
+
return result
|
|
78
|
+
|
|
79
|
+
def stream_generator():
|
|
80
|
+
tool_calls_buffer = {}
|
|
81
|
+
final_tool_calls = None
|
|
82
|
+
received_ids = {} # 用于保存每个index首次收到的ID
|
|
83
|
+
|
|
84
|
+
with httpx.stream("POST", f"{self.base_url}/chat/completions", json=payload, headers=headers, timeout=60) as response:
|
|
85
|
+
for line in response.iter_lines():
|
|
86
|
+
line = line.strip()
|
|
87
|
+
if line.startswith("data: "):
|
|
88
|
+
try:
|
|
89
|
+
data = json.loads(line[6:])
|
|
90
|
+
for choice in data.get("choices", []):
|
|
91
|
+
delta = choice.get("delta", {})
|
|
92
|
+
result = {"role": "assistant"}
|
|
93
|
+
|
|
94
|
+
# 处理普通内容
|
|
95
|
+
if "content" in delta:
|
|
96
|
+
result["content"] = delta["content"]
|
|
97
|
+
yield result
|
|
98
|
+
|
|
99
|
+
# 处理工具调用
|
|
100
|
+
if "tool_calls" in delta:
|
|
101
|
+
for tool_call in delta["tool_calls"]:
|
|
102
|
+
index = tool_call["index"]
|
|
103
|
+
|
|
104
|
+
# 初始化缓冲区
|
|
105
|
+
if index not in tool_calls_buffer:
|
|
106
|
+
tool_calls_buffer[index] = {
|
|
107
|
+
"index": index,
|
|
108
|
+
"function": {"arguments": ""},
|
|
109
|
+
"type": "",
|
|
110
|
+
"id": ""
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# 保留首次收到的ID
|
|
114
|
+
if tool_call.get("id") and index not in received_ids:
|
|
115
|
+
received_ids[index] = tool_call["id"]
|
|
116
|
+
|
|
117
|
+
# 更新字段(保留首次ID)
|
|
118
|
+
current = tool_calls_buffer[index]
|
|
119
|
+
current["id"] = received_ids.get(index, "")
|
|
120
|
+
current["type"] = tool_call.get("type") or current["type"]
|
|
121
|
+
|
|
122
|
+
# 处理函数参数
|
|
123
|
+
if tool_call.get("function"):
|
|
124
|
+
func = tool_call["function"]
|
|
125
|
+
current["function"]["name"] = func.get("name") or current["function"].get("name", "")
|
|
126
|
+
if func.get("arguments") is None:
|
|
127
|
+
continue
|
|
128
|
+
current["function"]["arguments"] += func.get("arguments", "")
|
|
129
|
+
|
|
130
|
+
# 暂存当前状态
|
|
131
|
+
final_tool_calls = [v for k, v in sorted(tool_calls_buffer.items())]
|
|
132
|
+
|
|
133
|
+
except json.JSONDecodeError:
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
# 流结束时处理最终工具调用
|
|
137
|
+
if final_tool_calls:
|
|
138
|
+
yield {
|
|
139
|
+
"role": "assistant",
|
|
140
|
+
"content": "",
|
|
141
|
+
"tool_calls": final_tool_calls,
|
|
142
|
+
"id": final_tool_calls[0]["id"] if final_tool_calls else ""
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return stream_generator()
|
tina/LLM/llama.py
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"""
|
|
2
|
+
编写者:王出日
|
|
3
|
+
日期:2024,12,13
|
|
4
|
+
版本?
|
|
5
|
+
|
|
6
|
+
将llama-cpp-python封装为需要的接口
|
|
7
|
+
llama.cpp Github地址:https://github.com/ggerganov/llama.cpphttps://github.com/ggerganov/llama.cpp
|
|
8
|
+
llama-cpp-python Github地址:https://github.com/abetlen/llama-cpp-python
|
|
9
|
+
tina类基于llama-cpp-python实现
|
|
10
|
+
使用更简单的语言描述让开发者更快的上手
|
|
11
|
+
tina是基于开源的qwen2.5-7b模型微调而来
|
|
12
|
+
qwen模型网址:https://github.com/QwenLM/Qwenhttps://github.com/QwenLM/Qwen
|
|
13
|
+
"""
|
|
14
|
+
import os
|
|
15
|
+
from typing import Union,Generator
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class llama:
|
|
20
|
+
def __init__(self,
|
|
21
|
+
path:str=os.path.join(os.path.dirname(__file__),'model','qwen2.5-7b-instruct-q4_k_m.gguf'),
|
|
22
|
+
device:str='gpu',
|
|
23
|
+
context_length:int=512,
|
|
24
|
+
GPU_n:int=-1,
|
|
25
|
+
verbose:bool=False
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
初始化tina类
|
|
29
|
+
Args:
|
|
30
|
+
path: 模型路径
|
|
31
|
+
device: cpu或gpu
|
|
32
|
+
context_length: 最大上下文长度,默认为512
|
|
33
|
+
GPU_n: 指定需要负载到GPU的模型层数,-1表示全部层负载到GPU的(不清楚模型内部实现不要动,在使用GPU是默认为-1)
|
|
34
|
+
verbose: 是否打印日志,默认不打印
|
|
35
|
+
"""
|
|
36
|
+
from llama_cpp import Llama
|
|
37
|
+
self.context_length = context_length
|
|
38
|
+
self._call = "LOCAL"
|
|
39
|
+
|
|
40
|
+
# 防止出现设备参数错误
|
|
41
|
+
if os.path.exists(path):
|
|
42
|
+
if not os.path.isfile(path):
|
|
43
|
+
raise ValueError("path(模型路径)必须是一个文件!")
|
|
44
|
+
else:
|
|
45
|
+
raise ValueError("path(模型路径)不存在!")
|
|
46
|
+
device_dict = {
|
|
47
|
+
'cpu': 'cpu',
|
|
48
|
+
'gpu': 'gpu',
|
|
49
|
+
'CPU': 'cpu',
|
|
50
|
+
'GPU': 'gpu',
|
|
51
|
+
'cuda': 'gpu',
|
|
52
|
+
'CUDA': 'gpu'
|
|
53
|
+
}
|
|
54
|
+
if device not in device_dict:
|
|
55
|
+
raise ValueError("device(设备)只能为cpu或gpu,对应参数为'cpu'或'gpu'")
|
|
56
|
+
if device == 'cpu': # cpu模式
|
|
57
|
+
self.model = Llama(path,verbose=verbose,n_ctx=context_length)
|
|
58
|
+
else: # gpu模式
|
|
59
|
+
self.model = Llama(path,n_gpu_layers=GPU_n,n_ctx=context_length,verbose=verbose)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def predict(self,
|
|
63
|
+
input_text:str = None,
|
|
64
|
+
sys_prompt:str='你的工作非常的出色!',
|
|
65
|
+
messages:list = None,
|
|
66
|
+
temperature:float=0.3,
|
|
67
|
+
top_p:float = 0.9,
|
|
68
|
+
top_k:int = 0,
|
|
69
|
+
min_p:float = 0,
|
|
70
|
+
stream =False,
|
|
71
|
+
format:str='text',
|
|
72
|
+
json_format:str='{}',
|
|
73
|
+
tools:list=[]
|
|
74
|
+
) -> Union[dict,Generator]:
|
|
75
|
+
"""
|
|
76
|
+
输入文本,生成文本,predict是ai为我取的名字
|
|
77
|
+
Args:
|
|
78
|
+
input_text: 输入文本
|
|
79
|
+
sys_prompt: 系统prompt,默认为"你的工作非常的出色!",就算是ai,让他们工作也需要鼓励!
|
|
80
|
+
temperature: 控制生成文本的随机性,默认0.3
|
|
81
|
+
top_p: 控制生成文本的多样性,默认0.9
|
|
82
|
+
top_k: 控制生成文本的多样性,默认0
|
|
83
|
+
min_p: 控制生成文本的多样性,默认0
|
|
84
|
+
stream: 是否流式输出,默认False
|
|
85
|
+
format: 输出格式,默认为text,可选json
|
|
86
|
+
json_format: json格式,默认为{}
|
|
87
|
+
"""
|
|
88
|
+
format_dict = {
|
|
89
|
+
'text': 'text',
|
|
90
|
+
'json': 'json_object'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if format not in format_dict:
|
|
94
|
+
raise ValueError("format(输出格式)只能为两种,一种为text,另一种为json,对应参数为'text'和'json'")
|
|
95
|
+
if format == 'text' and json_format!= '{}':
|
|
96
|
+
raise ValueError("json_format参数只对json格式有效!")
|
|
97
|
+
if format == 'json' and json_format == '{}':
|
|
98
|
+
raise ValueError("指定参数为json格式时,json_format参数不能为空!")
|
|
99
|
+
|
|
100
|
+
format = format_dict[format]
|
|
101
|
+
|
|
102
|
+
if messages != None and input_text == None:
|
|
103
|
+
if json_format != '{}':
|
|
104
|
+
messages.append({"role":"system","content":f"请按照{json_format}格式输出消息!"})
|
|
105
|
+
return self.completion(
|
|
106
|
+
messages = messages,
|
|
107
|
+
temperature = temperature,
|
|
108
|
+
top_p = top_p,
|
|
109
|
+
top_k = top_k,
|
|
110
|
+
min_p = min_p,
|
|
111
|
+
stream = stream,
|
|
112
|
+
tools=tools
|
|
113
|
+
)
|
|
114
|
+
elif messages != None and input_text != None:
|
|
115
|
+
raise ValueError("messages参数不能与input_text或sys_prompt参数同时使用!")
|
|
116
|
+
else:
|
|
117
|
+
return self.completion(input_text = input_text,
|
|
118
|
+
sys_prompt = sys_prompt,
|
|
119
|
+
temperature = temperature,
|
|
120
|
+
top_p = top_p,
|
|
121
|
+
top_k = top_k,
|
|
122
|
+
min_p = min_p,
|
|
123
|
+
stream = stream,
|
|
124
|
+
tools=tools)
|
|
125
|
+
|
|
126
|
+
def completion(self,
|
|
127
|
+
messages = None,
|
|
128
|
+
input_text = "",
|
|
129
|
+
sys_prompt = "",
|
|
130
|
+
temperature = 0.3,
|
|
131
|
+
top_p= 0.9,
|
|
132
|
+
top_k= 0,
|
|
133
|
+
min_p= 0,
|
|
134
|
+
format = 'text',
|
|
135
|
+
stream=False,
|
|
136
|
+
tools=[]
|
|
137
|
+
)-> Union[dict,Generator]:
|
|
138
|
+
"""
|
|
139
|
+
封装了llama-cpp-python的create_chat_completion方法
|
|
140
|
+
Args:
|
|
141
|
+
input_text: 输入文本
|
|
142
|
+
sys_prompt: 系统prompt
|
|
143
|
+
temperature: 控制生成文本的随机性,默认0.3
|
|
144
|
+
top_p: 控制生成文本的多样性
|
|
145
|
+
top_k: 控制生成文本的多样性
|
|
146
|
+
min_p: 控制生成文本的多样性
|
|
147
|
+
stream: 是否流式输出
|
|
148
|
+
tools: 工具列表
|
|
149
|
+
Returns:
|
|
150
|
+
输出文本
|
|
151
|
+
"""
|
|
152
|
+
if messages is not None:
|
|
153
|
+
completions = self.model.create_chat_completion(
|
|
154
|
+
messages=messages,
|
|
155
|
+
temperature=temperature,
|
|
156
|
+
top_p=top_p,
|
|
157
|
+
top_k=top_k,
|
|
158
|
+
min_p=min_p,
|
|
159
|
+
response_format={"type": format},
|
|
160
|
+
stream=stream,
|
|
161
|
+
tools=tools
|
|
162
|
+
)
|
|
163
|
+
else:
|
|
164
|
+
completions=self.model.create_chat_completion(
|
|
165
|
+
messages=[
|
|
166
|
+
{"role":"system","content":"你是一个中文大语言模型助手"},
|
|
167
|
+
{"role":"system","content":sys_prompt},
|
|
168
|
+
{"role":"user","content":input_text}
|
|
169
|
+
],
|
|
170
|
+
temperature=temperature,
|
|
171
|
+
top_p=top_p,
|
|
172
|
+
top_k=top_k,
|
|
173
|
+
min_p=min_p,
|
|
174
|
+
response_format={"type": format},
|
|
175
|
+
stream=stream,
|
|
176
|
+
tools=tools
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if not stream:
|
|
180
|
+
return completions['choices'][0]['message']
|
|
181
|
+
else:
|
|
182
|
+
return completions
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def chat(self,temperature=0.3):
|
|
188
|
+
"""
|
|
189
|
+
聊天模式,输入文本,生成文本,用于控制台调试
|
|
190
|
+
Args:
|
|
191
|
+
temperature: 控制生成文本的随机性,默认0.3
|
|
192
|
+
"""
|
|
193
|
+
messages = ''
|
|
194
|
+
print(self.predict("用户开始聊天,问好一句吧!")['content'],temperature)
|
|
195
|
+
while True:
|
|
196
|
+
input_text = input("\nuser:")
|
|
197
|
+
messages += "用户输入:"+input_text + '\n'
|
|
198
|
+
if input_text == "#exit":
|
|
199
|
+
break
|
|
200
|
+
massage = self.stream(
|
|
201
|
+
self.predict(input_text,
|
|
202
|
+
sys_prompt=f"之前的你与用户交流的记忆:{messages}\n",
|
|
203
|
+
stream=True,
|
|
204
|
+
temperature=temperature)
|
|
205
|
+
)
|
|
206
|
+
messages += "模型输出:"+massage + '\n'
|
|
207
|
+
if(len(messages)>100000):
|
|
208
|
+
messages = messages[-100000:]
|
|
209
|
+
|
|
210
|
+
def stream(self, completions):
|
|
211
|
+
"""
|
|
212
|
+
自己写的一个流式输出方法
|
|
213
|
+
Args:
|
|
214
|
+
completions: 生成的文本
|
|
215
|
+
"""
|
|
216
|
+
messages = ''
|
|
217
|
+
for chunk in completions:
|
|
218
|
+
delta = chunk["choices"][0]["delta"]
|
|
219
|
+
if 'role' in delta:
|
|
220
|
+
messages += delta['role'] + ': '
|
|
221
|
+
print(delta['role'], end=': ', flush=True)
|
|
222
|
+
elif 'content' in delta:
|
|
223
|
+
messages += delta['content']
|
|
224
|
+
print(delta['content'], end='', flush=True)
|
|
225
|
+
return messages
|
|
226
|
+
|
|
227
|
+
# def parser(self, completions):
|
|
228
|
+
# """
|
|
229
|
+
# 解析生成的文本
|
|
230
|
+
# Args:
|
|
231
|
+
# completions: 生成的文本
|
|
232
|
+
# """
|
|
233
|
+
# messages = ''
|
|
234
|
+
# for chunk in completions:
|
|
235
|
+
# delta = chunk["choices"][0]["delta"]
|
|
236
|
+
# if 'role' in delta:
|
|
237
|
+
# messages += delta['role'] + ': '
|
|
238
|
+
|
|
239
|
+
# elif 'content' in delta:
|
|
240
|
+
# messages += delta['content']
|
|
241
|
+
|
|
242
|
+
# return messages
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
if __name__ == '__main__':
|
|
247
|
+
test_text = """
|
|
248
|
+
柳夭在学校呆了一天,她一直在看书,我在想,我该怎么帮她。
|
|
249
|
+
张波在晚自习下课的时候,自然地靠在了我的旁边,他也和我一样装模做样的看着楼下的人群。
|
|
250
|
+
”我也想帮她,你说我们该怎么办?”
|
|
251
|
+
我诧异地看着他,他神秘地笑了笑。
|
|
252
|
+
“你看上去怎么好像什么都知道?”
|
|
253
|
+
我把事情告诉了他,他略有所思,我们安静了一会,他才问我,问题的关键是什么?
|
|
254
|
+
她的妈妈回来了,她的家人供她读书,不再提起嫁人的事...
|
|
255
|
+
他说,这些是关键吗?这是解决问题的方法。
|
|
256
|
+
“心冇,你知道为什么你会感觉自己做不到吗?因为你只是一个普通的高中生,你还没有插足别人家庭,帮别人家庭做主的能力,方法有很多,你却选择了一个自己最不可能做的到的。”
|
|
257
|
+
“我们要让她感受到关爱,我们可以有很多方法,你不是会画画吗?”
|
|
258
|
+
“我可以送一副画给她。”
|
|
259
|
+
“重要的不是画,而是你有把她当作朋友的那一份心。”
|
|
260
|
+
张波凝视着我,我好像知道我该怎么办了。
|
|
261
|
+
“我需要你的帮助,张波。”
|
|
262
|
+
上了这么久的学,好像我第一次发自内心的笑了。
|
|
263
|
+
张波的意思是,让她感觉自己又被真的在意,不是因为她是一个女生,一个生育工具。
|
|
264
|
+
我和他说,希望张好可以知道这件事,让她们女生寝室的多关注她一下。实际上,那天晚自习下课,老班把张好和她们寝室的女生悄悄地叫到办公室了。
|
|
265
|
+
我在办公室门口忐忑地走着,思考了许久之后,我鼓起勇气朝着被女生围住地老班走去。
|
|
266
|
+
10双眼睛盯着我,都是一副我是来干什么地看着我。
|
|
267
|
+
“你有什么事吗?”老班温柔地说。
|
|
268
|
+
我将柳夭的故事说了出来,她们先是怀疑,然后说,为什么她不直接和她们说,而是要直接出去哭呢,她为什么会觉得她们不会理解她呢?
|
|
269
|
+
“因为你们不是她,你们过的生活和她的不一样。”
|
|
270
|
+
“那你理解吗?”她们有些咄咄逼人。
|
|
271
|
+
“好了,同学们,心冇也是好心,他没有恶意”,老班停止了这场争议,她们安静了下来,一个个偷偷的扯了扯各自的衣袖。
|
|
272
|
+
“老班,我们知道怎么做了。”张好终于说话了,而且看了看我,女生们一连串的出去了,我从窗户外看向我们班,我能看见她趴在墙上看着这里。
|
|
273
|
+
老班微笑的看着我。
|
|
274
|
+
“她家确实有点特殊啊”,老班说,“虽然在之前很常见,没想到我又遇见了。”
|
|
275
|
+
“老班,为什么要这么说?”我是第一次和老班开口吧,开口还是不自然,或者对老师有种权威的害怕,老班的笑容很和谐,甚至有种不靠谱的感觉。
|
|
276
|
+
“她爷爷奶奶就他爸一个儿子,其他都是女儿,这样重男轻女挺正常,谁希望自家断种呢?”
|
|
277
|
+
“老班...我觉得不应该这么想...”
|
|
278
|
+
老班拍了拍我的肩。
|
|
279
|
+
“在你们这一代,也许就不一样了。”
|
|
280
|
+
老班的眼睛眯上一条缝,让我也放松了不少。
|
|
281
|
+
“老班,她妈妈去哪里了?”
|
|
282
|
+
“不知道,我也在想办法联系她,不过我不知道。”
|
|
283
|
+
“老班,她现在没有人管她了。”
|
|
284
|
+
“谁说的,我没有这么说哦。”
|
|
285
|
+
老班还是笑着,不过我已经知道了老班的意思,老班是一个好人,我想的问题,实际上他也想过了。
|
|
286
|
+
“谢谢老班。”
|
|
287
|
+
我朝着老班笑了笑,就走了。
|
|
288
|
+
张波在走廊上看着我,柳夭已经不在走廊上了,他和我一起走进了教室,一张纸条在我的桌子上。
|
|
289
|
+
“今天晚上可以吗?”
|
|
290
|
+
“你们俩好像在约会啊。”张波双手交叉在头后面,我没有过这种想法。
|
|
291
|
+
“你在说什么啊?”我小声地回应他,写下一个“好”字,回头看向她,她低着头在看书了"""
|
|
292
|
+
llm = tina(device='gpu',context_length=20480,verbose=False)
|
|
293
|
+
output = llm.predict(
|
|
294
|
+
input_text=test_text,
|
|
295
|
+
sys_prompt="总结文本",
|
|
296
|
+
temperature=0.3,
|
|
297
|
+
top_p=0.9,
|
|
298
|
+
top_k=0,
|
|
299
|
+
min_p=0,
|
|
300
|
+
stream=False,
|
|
301
|
+
format='text',
|
|
302
|
+
)
|
|
303
|
+
print(output['content'])
|
|
304
|
+
# response_format={
|
|
305
|
+
# "type": "json_object",
|
|
306
|
+
# },
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
编写者:王出日
|
|
3
|
+
日期:2024,12,1
|
|
4
|
+
版本?
|
|
5
|
+
使用通义大模型的词嵌入模型对中文文本进行编码
|
|
6
|
+
包含:
|
|
7
|
+
TextEmbedding类:用于对中文文本进行编码
|
|
8
|
+
"""
|
|
9
|
+
import dashscope
|
|
10
|
+
from http import HTTPStatus
|
|
11
|
+
from typing import Union
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
dashscope.api_key= "sk-aa328698ca6f4a7c9c0dde0b9851a772"
|
|
15
|
+
class TextEmbedding:
|
|
16
|
+
def __init__(self,model_version = "v1"):
|
|
17
|
+
"""
|
|
18
|
+
初始化通义大模型的词嵌入模型
|
|
19
|
+
:param model_version: 模型版本,默认为v1
|
|
20
|
+
"""
|
|
21
|
+
# self.cache = getCache()
|
|
22
|
+
if model_version == "v1":
|
|
23
|
+
self.model = dashscope.TextEmbedding.Models.text_embedding_v1
|
|
24
|
+
elif model_version == "v2":
|
|
25
|
+
self.model = dashscope.TextEmbedding.Models.text_embedding_v2
|
|
26
|
+
elif model_version == "v3":
|
|
27
|
+
self.model = dashscope.TextEmbedding.Models.text_embedding_v3
|
|
28
|
+
else:
|
|
29
|
+
raise ValueError("不存在该版本")
|
|
30
|
+
|
|
31
|
+
def embedding(self, text: Union[str, list]):
|
|
32
|
+
"""
|
|
33
|
+
对中文文本进行编码
|
|
34
|
+
Args:
|
|
35
|
+
text: 输入的中文文本
|
|
36
|
+
Returns:
|
|
37
|
+
文本的嵌入向量
|
|
38
|
+
"""
|
|
39
|
+
return self.strOrList(text)
|
|
40
|
+
|
|
41
|
+
def strOrList(self, text):
|
|
42
|
+
if isinstance(text, list):
|
|
43
|
+
return [self.textembedding(t).output["embeddings"][0]['embedding'] for t in text]
|
|
44
|
+
else:
|
|
45
|
+
return self.textembedding(text).output["embeddings"][0]['embedding']
|
|
46
|
+
|
|
47
|
+
def textembedding(self, text):
|
|
48
|
+
resp = dashscope.TextEmbedding.call(
|
|
49
|
+
model=self.model,
|
|
50
|
+
input=text
|
|
51
|
+
)
|
|
52
|
+
if resp.status_code == HTTPStatus.OK:
|
|
53
|
+
return resp
|
|
54
|
+
else:
|
|
55
|
+
print(resp)
|
|
56
|
+
raise ValueError("调用API失败")
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import faiss
|
|
2
|
+
|
|
3
|
+
from .embedding import Embedding
|
|
4
|
+
from ...core.manage import TinaFolderManager
|
|
5
|
+
from ..textSegments import TextSegments
|
|
6
|
+
from ..processFiles import fileToTxtByExten
|
|
7
|
+
|
|
8
|
+
def docToVec(file_path,model_path = None,dimesion=768,n=500,isCopyToTinaFolder:bool = False):
|
|
9
|
+
"""
|
|
10
|
+
将文本文件转换为向量,并建立Faiss索引。
|
|
11
|
+
Args:
|
|
12
|
+
file_path: 文本文件路径
|
|
13
|
+
dimesion: 向量维度
|
|
14
|
+
n: 每个文本分段的最大字数
|
|
15
|
+
Returns:
|
|
16
|
+
None
|
|
17
|
+
"""
|
|
18
|
+
text_segments = TextSegments(file_path)
|
|
19
|
+
text_embedding = Embedding(model_path=model_path)
|
|
20
|
+
faiss_index = faiss.IndexFlatL2(dimesion)
|
|
21
|
+
faiss_index_file = TinaFolderManager.getFaissIndex()
|
|
22
|
+
text_segments.segments(n,isCopyFileToTinaFolder=isCopyToTinaFolder)
|
|
23
|
+
for i in range(text_segments.getMaxId()):
|
|
24
|
+
text = text_segments.get(i+1)
|
|
25
|
+
if text == []:
|
|
26
|
+
continue
|
|
27
|
+
vec = text_embedding.embedding(text)
|
|
28
|
+
faiss_index.add(vec)
|
|
29
|
+
faiss.write_index(faiss_index, faiss_index_file)
|
|
30
|
+
print("已将文本文件转换为向量并建立Faiss索引。")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
from ...core.manage import TinaFolderManager
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Embedding:
|
|
10
|
+
def __init__(self, model_path: str = None, GPU_n: int = -1, log: bool = False):
|
|
11
|
+
from llama_cpp import Llama
|
|
12
|
+
if model_path is None:
|
|
13
|
+
model_path = TinaFolderManager.getEmbedingModel()
|
|
14
|
+
|
|
15
|
+
self.embeddingModel = Llama(model_path=model_path, embedding=True, n_gpu_layers=GPU_n, verbose=log)
|
|
16
|
+
|
|
17
|
+
def embedding(self, input_str: Union[str, list[str]]) -> np.ndarray:
|
|
18
|
+
if isinstance(input_str, str):
|
|
19
|
+
return np.array(self.embeddingModel.create_embedding(input_str)["data"][0]["embedding"]).reshape(1, -1)
|
|
20
|
+
elif isinstance(input_str, list):
|
|
21
|
+
embeddings = []
|
|
22
|
+
for i in input_str:
|
|
23
|
+
embedding = np.array(self.embeddingModel.create_embedding(i)["data"][0]["embedding"])
|
|
24
|
+
embeddings.append(embedding)
|
|
25
|
+
return np.array(embeddings)
|
|
26
|
+
else:
|
|
27
|
+
raise TypeError("input_str 参数只能是str或list[str]类型")
|
tina/RAG/__init__.py
ADDED
|
File without changes
|