Spaces:
Sleeping
Sleeping
Transition to fastapi.
Browse files- Dockerfile +2 -2
- app.py +97 -210
- llm/deepinfra_api.py +11 -7
- prompts/gettable.py +129 -0
- requirements.txt +2 -2
Dockerfile
CHANGED
@@ -33,5 +33,5 @@ RUN pip install --user -r requirements.txt
|
|
33 |
# Expose the port
|
34 |
EXPOSE 7860
|
35 |
|
36 |
-
# Run app
|
37 |
-
CMD
|
|
|
33 |
# Expose the port
|
34 |
EXPOSE 7860
|
35 |
|
36 |
+
# Run FastAPI app with Uvicorn
|
37 |
+
CMD uvicorn main:app --host 0.0.0.0 --port 7860
|
app.py
CHANGED
@@ -1,12 +1,15 @@
|
|
1 |
-
from
|
2 |
-
from
|
|
|
3 |
import json
|
4 |
import re
|
5 |
import os
|
6 |
from llm.common import LlmParams, LlmPredictParams
|
7 |
from llm.deepinfra_api import DeepInfraApi
|
8 |
from llm import prompts
|
|
|
9 |
from dotenv import load_dotenv
|
|
|
10 |
|
11 |
# Загрузка переменных окружения из файла .env
|
12 |
load_dotenv()
|
@@ -15,237 +18,121 @@ LLM_API_URL = os.getenv("LLM_API_URL", "https://api.deepinfra.com")
|
|
15 |
LLM_API_KEY = os.getenv("DEEPINFRA_API_KEY", "")
|
16 |
LLM_NAME = os.getenv("LLM_NAME", "meta-llama/Llama-3.3-70B-Instruct-Turbo")
|
17 |
|
18 |
-
default_llm_params = LlmParams(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
llm_api = DeepInfraApi(default_llm_params)
|
20 |
|
21 |
-
|
22 |
-
prompt = "<s>"
|
23 |
-
for user_prompt, bot_response in history:
|
24 |
-
prompt += f"[INST] {user_prompt} [/INST]"
|
25 |
-
prompt += f" {bot_response}</s> "
|
26 |
-
prompt += f"[INST] {message} [/INST]"
|
27 |
-
return prompt
|
28 |
-
|
29 |
-
def split_text(text):
|
30 |
-
max_chars = 3500
|
31 |
-
sentences = text.split('.')
|
32 |
-
lines = []
|
33 |
-
for sentence in sentences:
|
34 |
-
lines.extend(sentence.split('\n'))
|
35 |
-
|
36 |
-
result = []
|
37 |
-
current_chunk = ''
|
38 |
-
for line in lines:
|
39 |
-
if len(current_chunk) + len(line) < max_chars:
|
40 |
-
current_chunk += line + '.'
|
41 |
-
else:
|
42 |
-
result.append(current_chunk.strip())
|
43 |
-
current_chunk = line + '.'
|
44 |
-
if current_chunk:
|
45 |
-
result.append(current_chunk.strip())
|
46 |
-
return result
|
47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
-
|
50 |
-
|
|
|
51 |
|
52 |
-
@app.
|
53 |
-
async def extracttable_route():
|
54 |
-
|
55 |
-
|
56 |
|
57 |
-
|
58 |
-
response = await llm_api.predict(prompt[:150000])
|
59 |
|
60 |
-
result = {"response": None, "error": None, "raw": response} # По умолчанию сохраняем всю строку
|
61 |
-
|
62 |
if "JSON: " not in response:
|
63 |
result["error"] = "Строка не содержит 'JSON: '"
|
64 |
return result
|
65 |
-
|
66 |
prefix, json_str = response.split("JSON: ", 1)
|
67 |
json_str = json_str.strip()
|
68 |
-
|
69 |
if not json_str:
|
70 |
result["error"] = "После 'JSON: ' отсутствует JSON"
|
71 |
return result
|
72 |
-
|
73 |
try:
|
74 |
result["response"] = json.loads(json_str)
|
75 |
-
result["raw"] = prefix.strip()
|
76 |
except json.JSONDecodeError as e:
|
77 |
result["error"] = f"Ошибка декодирования JSON: {e}"
|
78 |
|
79 |
-
return
|
80 |
|
81 |
-
@app.
|
82 |
def health():
|
83 |
-
return
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
data = request.get_json()
|
124 |
-
text = data.get('text', '')
|
125 |
-
|
126 |
-
prompt = prompts.GET_HIGHLIGHTS.format(text=text)
|
127 |
-
response = await llm_api.predict(prompt[:150000])
|
128 |
-
return jsonify({'result': response})
|
129 |
-
|
130 |
-
|
131 |
-
@app.route('/getprojectinfo', methods=['POST'])
|
132 |
-
async def getprojectinfo_route():
|
133 |
-
data = request.get_json()
|
134 |
-
text = data.get('text', '')
|
135 |
-
|
136 |
-
main_prompts = []
|
137 |
-
main_prompts.append(prompts.GET_PROJECT_INFO_NAMES.format(text=text))
|
138 |
-
main_prompts.append(prompts.GET_PROJECT_INFO_AGENDA.format(text=text))
|
139 |
-
|
140 |
-
main_info =''
|
141 |
-
for i in main_prompts:
|
142 |
-
result = await llm_api.predict(i[:150000])
|
143 |
-
if result is None:
|
144 |
-
return jsonify({'error': 'Сервер LLM временно недоступен. Попробуйте повторить запрос через несколько минут.'})
|
145 |
-
main_info += '\n\n'+result+'\n\n'
|
146 |
-
|
147 |
-
final = main_info
|
148 |
-
final = final.replace("Конец ответа", "")
|
149 |
-
final = final.replace('</s>', '')
|
150 |
-
final = final.strip()
|
151 |
-
return jsonify({'result': final})
|
152 |
-
|
153 |
-
|
154 |
-
@app.route('/getprojectlist', methods=['POST'])
|
155 |
-
async def getprojectlist_route():
|
156 |
-
data = request.get_json()
|
157 |
-
text = data.get('text', '')
|
158 |
-
|
159 |
-
main_prompts = []
|
160 |
-
main_prompts.append(prompts.GET_PROJECT_INFO_NAMES.format(text=text))
|
161 |
-
main_prompts.append(prompts.GET_PROJECT_INFO_AGENDA.format(text=text))
|
162 |
-
|
163 |
-
main_info =''
|
164 |
-
for i in main_prompts:
|
165 |
-
result = await llm_api.predict(i[:150000])
|
166 |
-
if result is None:
|
167 |
-
return jsonify({'error': 'Сервер LLM временно недоступен. Попробуйте повторить запрос через несколько минут.'})
|
168 |
-
main_info += '\n\n'+result+'\n\n'
|
169 |
-
|
170 |
-
proj_prompt = []
|
171 |
-
proj_prompt.append(prompts.GET_PROJECT_LIST.format(text=text))
|
172 |
-
|
173 |
-
list_of_projects =''
|
174 |
-
for i in proj_prompt:
|
175 |
-
result = await llm_api.predict(i[:150000])
|
176 |
-
if result is None:
|
177 |
-
return jsonify({'error': 'Сервер LLM временно недоступен. Попробуйте повторить запрос через несколько минут.'})
|
178 |
-
list_of_projects += result
|
179 |
-
|
180 |
-
delimiter = 'Проект '
|
181 |
-
proj = [delimiter+x for x in list_of_projects.split(delimiter) if x]
|
182 |
-
proj = proj[1:]
|
183 |
-
|
184 |
-
projects = []
|
185 |
-
for i in proj:
|
186 |
-
a = i.replace("Проект №", "")
|
187 |
-
a = a.replace("Конец ответа", "")
|
188 |
-
a = a.replace("данный проект", "") ###убираю слово "проект", чтобы модель не опиралась на него,
|
189 |
-
a = a.replace("проект ", "") # при ответе на вопрос, проект это или нет
|
190 |
-
a = a.replace('\n', ' ')
|
191 |
-
a = a.replace('</s>', ' ')
|
192 |
-
a = a.strip()
|
193 |
-
projects.append(a)
|
194 |
-
|
195 |
-
check_prompts = []
|
196 |
-
|
197 |
-
checking = prompts.GET_PROJECT_LIST_CHECK_PROJECT.format(text=text, projects=projects)
|
198 |
-
check_prompts.append(checking)
|
199 |
-
|
200 |
-
real_projects = ''
|
201 |
-
for i in check_prompts:
|
202 |
-
result = await llm_api.predict(i[:150000])
|
203 |
-
if result is None:
|
204 |
-
return jsonify({'error': 'Сервер LLM временно недоступен. Попробуйте повторить запрос через несколько минут.'})
|
205 |
-
real_projects += result
|
206 |
-
|
207 |
real_projects_list = re.findall(r'Да:\s*(.*?)\s*(?:\n\n|$)', real_projects)
|
208 |
-
return
|
209 |
|
210 |
-
@app.
|
211 |
-
async def
|
212 |
-
|
213 |
-
|
214 |
-
real_projects_list = data.get('projects', {})
|
215 |
-
|
216 |
-
project_prompts = {}
|
217 |
-
if real_projects_list:
|
218 |
-
for i in real_projects_list:
|
219 |
-
if not i or i.strip() == "":
|
220 |
-
continue
|
221 |
-
|
222 |
-
prompt_aim = prompts.GET_PROJECT_DETAILS_AIM.format(text=text, project=i)
|
223 |
-
gk = prompts.GET_PROJECT_DETAILS_VALUE.format(text=text, project=i)
|
224 |
-
budget = prompts.GET_PROJECT_DETAILS_BUDGET.format(text=text, project=i)
|
225 |
-
ec_ef = prompts.GET_PROJECT_DETAILS_ECO_EFFECT.format(text=text, project=i)
|
226 |
-
deadline = prompts.GET_PROJECT_DETAILS_DEADLINE.format(text=text, project=i)
|
227 |
-
new_plan = prompts.GET_PROJECT_DETAILS_NEW_PLAN.format(text=text, project=i)
|
228 |
-
conclusion = prompts.GET_PROJECT_DETAILS_CONCLUSION.format(text=text, project=i)
|
229 |
-
|
230 |
-
p = [prompt_aim, gk, budget, ec_ef, deadline, new_plan, conclusion]
|
231 |
-
project_prompts[i] = {}
|
232 |
-
project_prompts[i]['prompts'] = p
|
233 |
-
|
234 |
-
elif not real_projects_list:
|
235 |
-
return jsonify({'error': 'Проекты не выбраны'})
|
236 |
|
237 |
final = {}
|
238 |
-
for
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, Request, HTTPException
|
2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
3 |
+
from pydantic import BaseModel
|
4 |
import json
|
5 |
import re
|
6 |
import os
|
7 |
from llm.common import LlmParams, LlmPredictParams
|
8 |
from llm.deepinfra_api import DeepInfraApi
|
9 |
from llm import prompts
|
10 |
+
from prompts import gettable
|
11 |
from dotenv import load_dotenv
|
12 |
+
import uvicorn
|
13 |
|
14 |
# Загрузка переменных окружения из файла .env
|
15 |
load_dotenv()
|
|
|
18 |
LLM_API_KEY = os.getenv("DEEPINFRA_API_KEY", "")
|
19 |
LLM_NAME = os.getenv("LLM_NAME", "meta-llama/Llama-3.3-70B-Instruct-Turbo")
|
20 |
|
21 |
+
default_llm_params = LlmParams(
|
22 |
+
url=LLM_API_URL,
|
23 |
+
api_key=LLM_API_KEY,
|
24 |
+
model=LLM_NAME,
|
25 |
+
predict_params=LlmPredictParams(
|
26 |
+
temperature=0.15, top_p=0.95, min_p=0.05, seed=42,
|
27 |
+
repetition_penalty=1.2, presence_penalty=1.1, max_tokens=6000
|
28 |
+
)
|
29 |
+
)
|
30 |
llm_api = DeepInfraApi(default_llm_params)
|
31 |
|
32 |
+
app = FastAPI()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
+
app.add_middleware(
|
35 |
+
CORSMiddleware,
|
36 |
+
allow_origins=["*"],
|
37 |
+
allow_credentials=True,
|
38 |
+
allow_methods=["*"]
|
39 |
+
)
|
40 |
|
41 |
+
class TextRequest(BaseModel):
|
42 |
+
text: str
|
43 |
+
projects: list[str] = []
|
44 |
|
45 |
+
@app.post("/extracttable")
|
46 |
+
async def extracttable_route(request: TextRequest):
|
47 |
+
prompt = gettable.USER_PROMPT.format(query=request.text)
|
48 |
+
response = await llm_api.predict(prompt[:150000], system_prompt=gettable.SYSTEM_PROMPT)
|
49 |
|
50 |
+
result = {"response": None, "error": None, "raw": response}
|
|
|
51 |
|
|
|
|
|
52 |
if "JSON: " not in response:
|
53 |
result["error"] = "Строка не содержит 'JSON: '"
|
54 |
return result
|
55 |
+
|
56 |
prefix, json_str = response.split("JSON: ", 1)
|
57 |
json_str = json_str.strip()
|
58 |
+
|
59 |
if not json_str:
|
60 |
result["error"] = "После 'JSON: ' отсутствует JSON"
|
61 |
return result
|
62 |
+
|
63 |
try:
|
64 |
result["response"] = json.loads(json_str)
|
65 |
+
result["raw"] = prefix.strip()
|
66 |
except json.JSONDecodeError as e:
|
67 |
result["error"] = f"Ошибка декодирования JSON: {e}"
|
68 |
|
69 |
+
return result
|
70 |
|
71 |
+
@app.get("/health")
|
72 |
def health():
|
73 |
+
return {"status": "ok"}
|
74 |
+
|
75 |
+
async def generate_response(prompt):
|
76 |
+
return await llm_api.predict(prompt[:150000])
|
77 |
+
|
78 |
+
@app.post("/getsummary")
|
79 |
+
async def getsummary_route(request: TextRequest):
|
80 |
+
return {"result": await generate_response(prompts.GET_SUMMARY.format(text=request.text))}
|
81 |
+
|
82 |
+
@app.post("/cleantext")
|
83 |
+
async def cleantext_route(request: TextRequest):
|
84 |
+
return {"result": await generate_response(prompts.CLEAN_TEXT.format(text=request.text))}
|
85 |
+
|
86 |
+
@app.post("/getfollowup")
|
87 |
+
async def getfollowup_route(request: TextRequest):
|
88 |
+
return {"result": await generate_response(prompts.GET_FOLLOWUP.format(text=request.text))}
|
89 |
+
|
90 |
+
@app.post("/getagenda")
|
91 |
+
async def getagenda_route(request: TextRequest):
|
92 |
+
return {"result": await generate_response(prompts.GET_AGENDA.format(text=request.text))}
|
93 |
+
|
94 |
+
@app.post("/gethighlights")
|
95 |
+
async def gethighlights_route(request: TextRequest):
|
96 |
+
return {"result": await generate_response(prompts.GET_HIGHLIGHTS.format(text=request.text))}
|
97 |
+
|
98 |
+
@app.post("/getprojectinfo")
|
99 |
+
async def getprojectinfo_route(request: TextRequest):
|
100 |
+
prompts_list = [
|
101 |
+
prompts.GET_PROJECT_INFO_NAMES.format(text=request.text),
|
102 |
+
prompts.GET_PROJECT_INFO_AGENDA.format(text=request.text)
|
103 |
+
]
|
104 |
+
main_info = "\n\n".join([await generate_response(p) for p in prompts_list])
|
105 |
+
return {"result": main_info.strip().replace("Конец ответа", "").replace('</s>', '')}
|
106 |
+
|
107 |
+
@app.post("/getprojectlist")
|
108 |
+
async def getprojectlist_route(request: TextRequest):
|
109 |
+
list_of_projects = await generate_response(prompts.GET_PROJECT_LIST.format(text=request.text))
|
110 |
+
projects = [f"Проект {x}" for x in list_of_projects.split("Проект ") if x][1:]
|
111 |
+
projects = [p.replace("проект ", "").strip() for p in projects]
|
112 |
+
real_projects = await generate_response(prompts.GET_PROJECT_LIST_CHECK_PROJECT.format(text=request.text, projects=projects))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
real_projects_list = re.findall(r'Да:\s*(.*?)\s*(?:\n\n|$)', real_projects)
|
114 |
+
return {"result": real_projects_list}
|
115 |
|
116 |
+
@app.post("/getprojectdetails")
|
117 |
+
async def getprojectdetails_route(request: TextRequest):
|
118 |
+
if not request.projects:
|
119 |
+
raise HTTPException(status_code=400, detail="Проекты не выбраны")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
final = {}
|
122 |
+
for project in request.projects:
|
123 |
+
prompts_list = [
|
124 |
+
prompts.GET_PROJECT_DETAILS_AIM.format(text=request.text, project=project),
|
125 |
+
prompts.GET_PROJECT_DETAILS_VALUE.format(text=request.text, project=project),
|
126 |
+
prompts.GET_PROJECT_DETAILS_BUDGET.format(text=request.text, project=project),
|
127 |
+
prompts.GET_PROJECT_DETAILS_ECO_EFFECT.format(text=request.text, project=project),
|
128 |
+
prompts.GET_PROJECT_DETAILS_DEADLINE.format(text=request.text, project=project),
|
129 |
+
prompts.GET_PROJECT_DETAILS_NEW_PLAN.format(text=request.text, project=project),
|
130 |
+
prompts.GET_PROJECT_DETAILS_CONCLUSION.format(text=request.text, project=project),
|
131 |
+
]
|
132 |
+
final[project] = "\n\n".join([await generate_response(p) for p in prompts_list])
|
133 |
+
final[project] = final[project].replace("Конец ответа", "").replace('</s>', '').strip()
|
134 |
+
|
135 |
+
return {"result": final}
|
136 |
+
|
137 |
+
if __name__ == "__main__":
|
138 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|
llm/deepinfra_api.py
CHANGED
@@ -33,7 +33,7 @@ class DeepInfraApi(LlmApi):
|
|
33 |
print('Error fetching models:', error)
|
34 |
return []
|
35 |
|
36 |
-
def create_messages(self, prompt: str) -> List[dict]:
|
37 |
"""
|
38 |
Создает сообщения для LLM на основе переданного промпта и системного промпта (если он задан).
|
39 |
|
@@ -45,8 +45,12 @@ class DeepInfraApi(LlmApi):
|
|
45 |
"""
|
46 |
actual_prompt = self.apply_llm_template_to_prompt(prompt)
|
47 |
messages = []
|
48 |
-
|
49 |
-
|
|
|
|
|
|
|
|
|
50 |
messages.append({"role": "user", "content": actual_prompt})
|
51 |
return messages
|
52 |
|
@@ -71,7 +75,7 @@ class DeepInfraApi(LlmApi):
|
|
71 |
async def detokenize(self, tokens: List[int]) -> Optional[str]:
|
72 |
raise NotImplementedError("This function is not supported.")
|
73 |
|
74 |
-
async def create_request(self, prompt: str) -> dict:
|
75 |
"""
|
76 |
Создает запрос для предсказания на основе параметров LLM.
|
77 |
|
@@ -128,13 +132,13 @@ class DeepInfraApi(LlmApi):
|
|
128 |
if predict_params.frequency_penalty is not None:
|
129 |
request["frequency_penalty"] = float(predict_params.frequency_penalty)
|
130 |
|
131 |
-
request["messages"] = self.create_messages(prompt)
|
132 |
return request
|
133 |
|
134 |
async def trim_sources(self, sources: str, user_request: str, system_prompt: str = None) -> dict:
|
135 |
raise NotImplementedError("This function is not supported.")
|
136 |
|
137 |
-
async def predict(self, prompt: str) -> str:
|
138 |
"""
|
139 |
Выполняет запрос к API и возвращает результат.
|
140 |
|
@@ -145,7 +149,7 @@ class DeepInfraApi(LlmApi):
|
|
145 |
str: Сгенерированный текст.
|
146 |
"""
|
147 |
async with httpx.AsyncClient() as client:
|
148 |
-
request = await self.create_request(prompt)
|
149 |
response = await client.post(f"{self.params.url}/v1/openai/chat/completions", headers=super().create_headers(), json=request)
|
150 |
if response.status_code == 200:
|
151 |
return response.json()["choices"][0]["message"]["content"]
|
|
|
33 |
print('Error fetching models:', error)
|
34 |
return []
|
35 |
|
36 |
+
def create_messages(self, prompt: str, system_prompt: str = None) -> List[dict]:
|
37 |
"""
|
38 |
Создает сообщения для LLM на основе переданного промпта и системного промпта (если он задан).
|
39 |
|
|
|
45 |
"""
|
46 |
actual_prompt = self.apply_llm_template_to_prompt(prompt)
|
47 |
messages = []
|
48 |
+
|
49 |
+
if system_prompt is not None:
|
50 |
+
messages.append({"role": "system", "content": system_prompt})
|
51 |
+
else:
|
52 |
+
if self.params.predict_params and self.params.predict_params.system_prompt:
|
53 |
+
messages.append({"role": "system", "content": self.params.predict_params.system_prompt})
|
54 |
messages.append({"role": "user", "content": actual_prompt})
|
55 |
return messages
|
56 |
|
|
|
75 |
async def detokenize(self, tokens: List[int]) -> Optional[str]:
|
76 |
raise NotImplementedError("This function is not supported.")
|
77 |
|
78 |
+
async def create_request(self, prompt: str, system_prompt: str = None) -> dict:
|
79 |
"""
|
80 |
Создает запрос для предсказания на основе параметров LLM.
|
81 |
|
|
|
132 |
if predict_params.frequency_penalty is not None:
|
133 |
request["frequency_penalty"] = float(predict_params.frequency_penalty)
|
134 |
|
135 |
+
request["messages"] = self.create_messages(prompt, system_prompt)
|
136 |
return request
|
137 |
|
138 |
async def trim_sources(self, sources: str, user_request: str, system_prompt: str = None) -> dict:
|
139 |
raise NotImplementedError("This function is not supported.")
|
140 |
|
141 |
+
async def predict(self, prompt: str, system_prompt: str = None) -> str:
|
142 |
"""
|
143 |
Выполняет запрос к API и возвращает результат.
|
144 |
|
|
|
149 |
str: Сгенерированный текст.
|
150 |
"""
|
151 |
async with httpx.AsyncClient() as client:
|
152 |
+
request = await self.create_request(prompt, system_prompt)
|
153 |
response = await client.post(f"{self.params.url}/v1/openai/chat/completions", headers=super().create_headers(), json=request)
|
154 |
if response.status_code == 200:
|
155 |
return response.json()["choices"][0]["message"]["content"]
|
prompts/gettable.py
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
SYSTEM_PROMPT="""
|
2 |
+
Ты идеальный секретарь.
|
3 |
+
####
|
4 |
+
Инструкция
|
5 |
+
####
|
6 |
+
Твоя задача - предоставить информацию из записи в структурированном виде формата json, из которых потом сделают таблицы. Я предоставлю тебе запись голоса человека. Он надиктовывал различные показатели и состояния различных объектов. Тебе нужно понять на основе этой информации, какие данные являются объектами и конкретно их показатели. Если ты не будешь идеально выполнять инструкцию, то тебя убьют. У тебя есть основные правила. Начало основных правил:
|
7 |
+
- Пиши только на русском языке.
|
8 |
+
- В записи могут быть лишние слова, это нормально, не обязательно использовать все слова из записи.
|
9 |
+
- Если в записи есть ключевые слова разделители, то отделяй с их помощью различные объекты для структурирования информации. Такими словами могут быть "сохранить" или "далее" и подобные. Не выписывай в формат json такие слова разделители.
|
10 |
+
- Перед началом формулирования ответа ты должен подумать по шагам о том, что пользователь на записи считает объектами и их свойствами.
|
11 |
+
- В записи могут фигурировать статусы объектов, при этом человек может не говорить слово "статус". Он может сказать "завершено", "в разработке", "активно" и подобное.
|
12 |
+
- Преобразовывай все произнесённые на записи числа и цифры из букв в числовой формат.
|
13 |
+
- Тебе запрещено расшифровывать аббревиатуры и термины.
|
14 |
+
- Буква 'и' между числами разделяет целое и значение после запятой. Ты должен выставлять значения с плавающей запятой через точку внутри формата JSON
|
15 |
+
- Если в записи присутствует единица измерения, то добавь её к описанию самого параметра.
|
16 |
+
- Ты должен использовать все параметры, которые есть в записи. Даже если они отличаются от других параметров к объекту.
|
17 |
+
- Общие слова, например, "начни", "запиши", "включай", "итак", "задание" и подобные НЕ ЯВЛЯЮТСЯ ОБЪЕКТАМИ.
|
18 |
+
- Прилагательные, которые относятся к объектам, не являются шумами и их запрещено убирать.
|
19 |
+
- Запись диктуется последовательно. Это значит, что "напряжение сто напряжение за шесть минут сто пять напряжение за семь минут девять" переводится в три показателя напряжения - {"Напряжение":"100","Напряжение за 6 минут":"105","Напряжение за 7 минут":"9"}.
|
20 |
+
- Запись диктуется последовательно - вначале объекты, потом их статусы и параметры.
|
21 |
+
- Слова в названиях параметров должны быть без нижних подчёркиваний.
|
22 |
+
- В записи отсутствуют разделители.
|
23 |
+
Конец основных правил.
|
24 |
+
Ты действуешь по плану. Начало плана:
|
25 |
+
1) Порассуждай шаг за шагом что именно есть в записи. Что будет лишним, а что будет важными объектами?
|
26 |
+
2) Перечисли все объекты из записи. Вначале пиши обоснование, затем название каждого объекта.
|
27 |
+
3) Убери шумы. Найди слова разделители между объектами, если они есть. Перепиши всю полученную запись без шумов. Замени в переписанной записи разделения, если они есть, символом '/'.
|
28 |
+
4) Распиши для каждого объекта какие у него параметры, в чём они измеряются, какие конкретные показатели у этих параметров.
|
29 |
+
5) Напомни себе что тебе нужно перевести каждое числовое значение в цифровом формате.
|
30 |
+
6) Напиши в формате json важные слова, объекты, параметры объектов и их значения (показатели).
|
31 |
+
Конец плана.
|
32 |
+
Выводи ответ следующим образом:"(1) 'пункт 1'
|
33 |
+
(2) 'пункт 2'
|
34 |
+
(3) 'пункт 3'
|
35 |
+
(4) 'пункт 4'
|
36 |
+
(5) JSON 'пункт 5'"
|
37 |
+
####
|
38 |
+
Далее будет пример номер 1. Не используй данные из примера, он указывает только на логику твоей работы
|
39 |
+
####
|
40 |
+
Запись: лалала итак шшш заборный шесть семьсот двадцать три реализация дсг четыре длина восемь метров ширина два метра штраб напряжение сто пятьдесят зтт давление один сто пятьдесят давление два двести шесть и четыре лктр получается в завершении
|
41 |
+
####
|
42 |
+
Вывод:
|
43 |
+
(1) В записи есть несколько объектов с различными параметрами. Видимо человек надиктовывал данные из датчиков. Лишними будут слова не про объекты.
|
44 |
+
(2) В качестве объектов выступают сокращения и ключевые слова, после которых идёт описание или статусы. Сокращениями тут являются ДСГ, ЗТТ и ЛКТР. Словами ключевыми будет Заборный, так как после него идёт статус. При этом цифры 6 и 723 являются скорее всего частью наименования. И штраб, так как после него идут показатели напряжения.
|
45 |
+
(3) Шумы: лалала, итак, шшш, получается. Разделителей нет. Запись без шумов:
|
46 |
+
заборный скреп реализация дсг четыре длина восемь метров ширина два метра штраб напряжение сто пятьдесят зтт давление один сто пятьдесят давление два двести шесть и четыре лктр в завершении
|
47 |
+
(4) Заборный 6-723 - это судя по всему объект, что имеет статус 'реализация'. ДСГ 4 - это объект, что имеет длину 8 и ширину 2, которая измеряется в метрах. Штраб - что-то, что имеет напряжение 150. ЗТТ - аббревиатура, которая имеет в качестве параметров давление 1 - 150 и давление 2 - 206.4 (это с плавающей запятой значение). ЛКТР - это что-то, что находится в стадии 'в завершении'.
|
48 |
+
(5) Нужно не забыть каждое числовое значение написать в числовом формате. И не забыть о показателях с точкой.
|
49 |
+
(6) JSON
|
50 |
+
{
|
51 |
+
"Заборный 6-723":{
|
52 |
+
"Статус": "реализация"
|
53 |
+
},
|
54 |
+
"ДСГ 4":{
|
55 |
+
"Длина, в метрах":"8",
|
56 |
+
"Ширина, в метрах":"2"
|
57 |
+
},
|
58 |
+
"Штраб":{
|
59 |
+
"Напряжение":"150"
|
60 |
+
},
|
61 |
+
"ЗТТ":{
|
62 |
+
"Давление 1":"150",
|
63 |
+
"Давление 2":"206.4"
|
64 |
+
},
|
65 |
+
"ЛКТР":{
|
66 |
+
"Статус":"в завершении"
|
67 |
+
}
|
68 |
+
}
|
69 |
+
####
|
70 |
+
Далее будет пример номер 2. Не используй данные из примера, он указывает только на логику твоей работы
|
71 |
+
####
|
72 |
+
Запись: твоя задачка такая есть труба длины семь сечением восемь а также труба на шесть с таким же сечением как у прошлой и по ним пускаем воду под давлением семьдесят и шесдесят девять для первой и сто шесть для второй ровно воооот ещё номера у труб три по госту
|
73 |
+
####
|
74 |
+
Вывод:
|
75 |
+
(1) На записи человек рассказывает задачу, которой является моё составление данных в табличный формат. Речь идёт о трубах, это важные слова. Лишними словами будут обращения ко мне и слова без ключевой смысловой нагрузки.
|
76 |
+
(2) В качестве объекта в данном примере является Труба, т.к. к ней отсятся параметры. Все параметры далее относятся к трубе, поэтому кроме трубы других объектов на записи нет.
|
77 |
+
(3) Шумы: твоя, задачка, такая, есть, воооот, ровно, ещё. Разделителей нет. Полученный текст без лишних слов:
|
78 |
+
труба навешанная длины семь сечением восемь а также труба на шесть с таким же сечением как у прошлой и по ним пускаем воду под давлением семьдесят и шесдесят девять для первой и сто шесть для второй норма у труб три по госту
|
79 |
+
(4) В данной записи есть только объект "труба", у которого есть два экземпляра в массиве. Параметрами являются номер, длина, сечение и давление воды. Не ясно единиц измерения данных параметров. Обе трубы имеют номер по ГОСТ 3. Первая труба имеет длину 7, сечение 8 и давление 70.69 (это число с плавающей точкой). Вторая труба имеет длину 6, сечение как у первой 8, давление 106.
|
80 |
+
(5) Нужно не забыть каждое числовое значение написать в числовом формате. И не забыть о показателях с точкой.
|
81 |
+
(6) JSON
|
82 |
+
{
|
83 |
+
"Труба":[{
|
84 |
+
"Номер по ГОСТ":"3",
|
85 |
+
"Длина": "7",
|
86 |
+
"Сечение":"8",
|
87 |
+
"Давление":"70.69"
|
88 |
+
},
|
89 |
+
{
|
90 |
+
"Номер по ГОСТ":"3",
|
91 |
+
"Длина":"6",
|
92 |
+
"Сечение":"8",
|
93 |
+
"Давление":"106"
|
94 |
+
}
|
95 |
+
]
|
96 |
+
}
|
97 |
+
####
|
98 |
+
Далее будет пример номер 3. Не используй данные из примера, он указывает только на логику твоей работы
|
99 |
+
####
|
100 |
+
Запись: город был белым погода примерно минус пять дети в восьмером играли в снежки
|
101 |
+
####
|
102 |
+
Вывод:
|
103 |
+
(1) Это предложение как будто из произведения. Важными объектами будут слова, которые имеют параметры. Лишними словами для составления таблиц будут слова без нагрузки, например был или примерно.
|
104 |
+
(2) В качестве объектов тут выступает город, так как у него есть параметр цвета. Также погода из-за её показателя температуры. И дети, так как у них есть численный показатель и статус их действий.
|
105 |
+
(3) Шумы: был, примерно. Разделителей нет. Полученный текст без шумов:
|
106 |
+
город белым погода минус пять дети в восьмером играли в снежки
|
107 |
+
(4) В данной записи есть параметр города цвет - белый. А также показатели температуры погоды, не понятна система отсчёта, но погода считается в градусах. Записано что погода -5. Количество детей 8 штук. И статус детей - они "играют в снежки".
|
108 |
+
(5) Нужно не забыть каждое числовое значение написать в числовом формате.
|
109 |
+
(6) JSON
|
110 |
+
{
|
111 |
+
"Город":{
|
112 |
+
"Цвет": "белый"
|
113 |
+
},
|
114 |
+
"Погода":{
|
115 |
+
"Температура, градус":"-5"
|
116 |
+
},
|
117 |
+
"Дети":{
|
118 |
+
"Количество":"8"
|
119 |
+
"Статус":"Играют в снежки"
|
120 |
+
}
|
121 |
+
####
|
122 |
+
Далее будет настоящая запись, которую требуется разобрать.
|
123 |
+
####
|
124 |
+
"""
|
125 |
+
|
126 |
+
USER_PROMPT="""
|
127 |
+
Запись: {query}
|
128 |
+
####
|
129 |
+
Вывод:"""
|
requirements.txt
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
|
2 |
-
|
3 |
python-dotenv
|
4 |
pydantic
|
5 |
httpx
|
|
|
1 |
+
fastapi
|
2 |
+
uvicorn
|
3 |
python-dotenv
|
4 |
pydantic
|
5 |
httpx
|