KevinHuSh
commited on
Commit
·
e4c23fc
1
Parent(s):
4a674c0
fix file preview in file management (#1151)
Browse files### What problem does this PR solve?
fix file preview in file management
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
- api/apps/canvas_app.py +157 -0
- api/apps/file_app.py +4 -3
- api/db/services/canvas_service.py +26 -0
- api/db/services/task_service.py +10 -0
- docker/docker-compose-CN-oc9.yml +1 -0
- docker/docker-compose-CN.yml +1 -0
- docker/docker-compose.yml +1 -0
- rag/app/picture.py +1 -5
- rag/llm/cv_model.py +1 -1
- rag/llm/embedding_model.py +1 -2
api/apps/canvas_app.py
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#
|
2 |
+
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
|
3 |
+
#
|
4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5 |
+
# you may not use this file except in compliance with the License.
|
6 |
+
# You may obtain a copy of the License at
|
7 |
+
#
|
8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9 |
+
#
|
10 |
+
# Unless required by applicable law or agreed to in writing, software
|
11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 |
+
# See the License for the specific language governing permissions and
|
14 |
+
# limitations under the License.
|
15 |
+
#
|
16 |
+
import json
|
17 |
+
from functools import partial
|
18 |
+
|
19 |
+
from flask import request, Response
|
20 |
+
from flask_login import login_required, current_user
|
21 |
+
|
22 |
+
from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService
|
23 |
+
from api.utils import get_uuid
|
24 |
+
from api.utils.api_utils import get_json_result, server_error_response, validate_request
|
25 |
+
from graph.canvas import Canvas
|
26 |
+
|
27 |
+
|
28 |
+
@manager.route('/templates', methods=['GET'])
|
29 |
+
@login_required
|
30 |
+
def templates():
|
31 |
+
return get_json_result(data=[c.to_dict() for c in CanvasTemplateService.get_all()])
|
32 |
+
|
33 |
+
|
34 |
+
@manager.route('/list', methods=['GET'])
|
35 |
+
@login_required
|
36 |
+
def canvas_list():
|
37 |
+
|
38 |
+
return get_json_result(data=[c.to_dict() for c in UserCanvasService.query(user_id=current_user.id)])
|
39 |
+
|
40 |
+
|
41 |
+
@manager.route('/rm', methods=['POST'])
|
42 |
+
@validate_request("canvas_ids")
|
43 |
+
@login_required
|
44 |
+
def rm():
|
45 |
+
for i in request.json["canvas_ids"]:
|
46 |
+
UserCanvasService.delete_by_id(i)
|
47 |
+
return get_json_result(data=True)
|
48 |
+
|
49 |
+
|
50 |
+
@manager.route('/set', methods=['POST'])
|
51 |
+
@validate_request("dsl", "title")
|
52 |
+
@login_required
|
53 |
+
def save():
|
54 |
+
req = request.json
|
55 |
+
req["user_id"] = current_user.id
|
56 |
+
if not isinstance(req["dsl"], str):req["dsl"] = json.dumps(req["dsl"], ensure_ascii=False)
|
57 |
+
|
58 |
+
req["dsl"] = json.loads(req["dsl"])
|
59 |
+
if "id" not in req:
|
60 |
+
if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip()):
|
61 |
+
return server_error_response(ValueError("Duplicated title."))
|
62 |
+
req["id"] = get_uuid()
|
63 |
+
if not UserCanvasService.save(**req):
|
64 |
+
return server_error_response("Fail to save canvas.")
|
65 |
+
else:
|
66 |
+
UserCanvasService.update_by_id(req["id"], req)
|
67 |
+
|
68 |
+
return get_json_result(data=req)
|
69 |
+
|
70 |
+
|
71 |
+
@manager.route('/get/<canvas_id>', methods=['GET'])
|
72 |
+
@login_required
|
73 |
+
def get(canvas_id):
|
74 |
+
e, c = UserCanvasService.get_by_id(canvas_id)
|
75 |
+
if not e:
|
76 |
+
return server_error_response("canvas not found.")
|
77 |
+
return get_json_result(data=c.to_dict())
|
78 |
+
|
79 |
+
|
80 |
+
@manager.route('/completion', methods=['POST'])
|
81 |
+
@validate_request("id")
|
82 |
+
@login_required
|
83 |
+
def run():
|
84 |
+
req = request.json
|
85 |
+
stream = req.get("stream", True)
|
86 |
+
e, cvs = UserCanvasService.get_by_id(req["id"])
|
87 |
+
if not e:
|
88 |
+
return server_error_response("canvas not found.")
|
89 |
+
|
90 |
+
if not isinstance(cvs.dsl, str):
|
91 |
+
cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False)
|
92 |
+
|
93 |
+
final_ans = {"reference": [], "content": ""}
|
94 |
+
try:
|
95 |
+
canvas = Canvas(cvs.dsl, current_user.id)
|
96 |
+
print(canvas)
|
97 |
+
if "message" in req:
|
98 |
+
canvas.messages.append({"role": "user", "content": req["message"]})
|
99 |
+
canvas.add_user_input(req["message"])
|
100 |
+
answer = canvas.run(stream=stream)
|
101 |
+
except Exception as e:
|
102 |
+
return server_error_response(e)
|
103 |
+
|
104 |
+
if stream:
|
105 |
+
assert isinstance(answer, partial)
|
106 |
+
|
107 |
+
def sse():
|
108 |
+
nonlocal answer, cvs
|
109 |
+
try:
|
110 |
+
for ans in answer():
|
111 |
+
for k in ans.keys():
|
112 |
+
final_ans[k] = ans[k]
|
113 |
+
ans = {"answer": ans["content"], "reference": ans.get("reference", [])}
|
114 |
+
yield "data:" + json.dumps({"retcode": 0, "retmsg": "", "data": ans}, ensure_ascii=False) +"\n\n"
|
115 |
+
|
116 |
+
canvas.messages.append({"role": "assistant", "content": final_ans["content"]})
|
117 |
+
if "reference" in final_ans:
|
118 |
+
canvas.reference.append(final_ans["reference"])
|
119 |
+
cvs.dsl = json.loads(str(canvas))
|
120 |
+
UserCanvasService.update_by_id(req["id"], cvs.to_dict())
|
121 |
+
except Exception as e:
|
122 |
+
yield "data:" + json.dumps({"retcode": 500, "retmsg": str(e),
|
123 |
+
"data": {"answer": "**ERROR**: " + str(e), "reference": []}},
|
124 |
+
ensure_ascii=False) + "\n\n"
|
125 |
+
yield "data:" + json.dumps({"retcode": 0, "retmsg": "", "data": True}, ensure_ascii=False) + "\n\n"
|
126 |
+
|
127 |
+
resp = Response(sse(), mimetype="text/event-stream")
|
128 |
+
resp.headers.add_header("Cache-control", "no-cache")
|
129 |
+
resp.headers.add_header("Connection", "keep-alive")
|
130 |
+
resp.headers.add_header("X-Accel-Buffering", "no")
|
131 |
+
resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")
|
132 |
+
return resp
|
133 |
+
|
134 |
+
canvas.messages.append({"role": "assistant", "content": final_ans["content"]})
|
135 |
+
if "reference" in final_ans:
|
136 |
+
canvas.reference.append(final_ans["reference"])
|
137 |
+
cvs.dsl = json.loads(str(canvas))
|
138 |
+
UserCanvasService.update_by_id(req["id"], cvs.to_dict())
|
139 |
+
return get_json_result(data=req["dsl"])
|
140 |
+
|
141 |
+
|
142 |
+
@manager.route('/reset', methods=['POST'])
|
143 |
+
@validate_request("canvas_id")
|
144 |
+
@login_required
|
145 |
+
def reset():
|
146 |
+
req = request.json
|
147 |
+
try:
|
148 |
+
user_canvas = UserCanvasService.get_by_id(req["canvas_id"])
|
149 |
+
canvas = Canvas(req["dsl"], current_user.id)
|
150 |
+
canvas.reset()
|
151 |
+
req["dsl"] = json.loads(str(canvas))
|
152 |
+
UserCanvasService.update_by_id(req["canvas_id"], dsl=req["dsl"])
|
153 |
+
return get_json_result(data=req["dsl"])
|
154 |
+
except Exception as e:
|
155 |
+
return server_error_response(e)
|
156 |
+
|
157 |
+
|
api/apps/file_app.py
CHANGED
@@ -331,8 +331,8 @@ def get(file_id):
|
|
331 |
e, file = FileService.get_by_id(file_id)
|
332 |
if not e:
|
333 |
return get_data_error_result(retmsg="Document not found!")
|
334 |
-
|
335 |
-
response = flask.make_response(MINIO.get(
|
336 |
ext = re.search(r"\.([^.]+)$", file.name)
|
337 |
if ext:
|
338 |
if file.type == FileType.VISUAL.value:
|
@@ -345,7 +345,8 @@ def get(file_id):
|
|
345 |
return response
|
346 |
except Exception as e:
|
347 |
return server_error_response(e)
|
348 |
-
|
|
|
349 |
@manager.route('/mv', methods=['POST'])
|
350 |
@login_required
|
351 |
@validate_request("src_file_ids", "dest_file_id")
|
|
|
331 |
e, file = FileService.get_by_id(file_id)
|
332 |
if not e:
|
333 |
return get_data_error_result(retmsg="Document not found!")
|
334 |
+
b, n = File2DocumentService.get_minio_address(file_id=file_id)
|
335 |
+
response = flask.make_response(MINIO.get(b, n))
|
336 |
ext = re.search(r"\.([^.]+)$", file.name)
|
337 |
if ext:
|
338 |
if file.type == FileType.VISUAL.value:
|
|
|
345 |
return response
|
346 |
except Exception as e:
|
347 |
return server_error_response(e)
|
348 |
+
|
349 |
+
|
350 |
@manager.route('/mv', methods=['POST'])
|
351 |
@login_required
|
352 |
@validate_request("src_file_ids", "dest_file_id")
|
api/db/services/canvas_service.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#
|
2 |
+
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
|
3 |
+
#
|
4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5 |
+
# you may not use this file except in compliance with the License.
|
6 |
+
# You may obtain a copy of the License at
|
7 |
+
#
|
8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9 |
+
#
|
10 |
+
# Unless required by applicable law or agreed to in writing, software
|
11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 |
+
# See the License for the specific language governing permissions and
|
14 |
+
# limitations under the License.
|
15 |
+
#
|
16 |
+
from datetime import datetime
|
17 |
+
import peewee
|
18 |
+
from api.db.db_models import DB, API4Conversation, APIToken, Dialog, CanvasTemplate, UserCanvas
|
19 |
+
from api.db.services.common_service import CommonService
|
20 |
+
|
21 |
+
|
22 |
+
class CanvasTemplateService(CommonService):
|
23 |
+
model = CanvasTemplate
|
24 |
+
|
25 |
+
class UserCanvasService(CommonService):
|
26 |
+
model = UserCanvas
|
api/db/services/task_service.py
CHANGED
@@ -13,6 +13,7 @@
|
|
13 |
# See the License for the specific language governing permissions and
|
14 |
# limitations under the License.
|
15 |
#
|
|
|
16 |
import random
|
17 |
|
18 |
from api.db.db_utils import bulk_insert_into_db
|
@@ -102,6 +103,15 @@ class TaskService(CommonService):
|
|
102 |
@classmethod
|
103 |
@DB.connection_context()
|
104 |
def update_progress(cls, id, info):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
with DB.lock("update_progress", -1):
|
106 |
if info["progress_msg"]:
|
107 |
cls.model.update(progress_msg=cls.model.progress_msg + "\n" + info["progress_msg"]).where(
|
|
|
13 |
# See the License for the specific language governing permissions and
|
14 |
# limitations under the License.
|
15 |
#
|
16 |
+
import os
|
17 |
import random
|
18 |
|
19 |
from api.db.db_utils import bulk_insert_into_db
|
|
|
103 |
@classmethod
|
104 |
@DB.connection_context()
|
105 |
def update_progress(cls, id, info):
|
106 |
+
if os.environ.get("MACOS"):
|
107 |
+
if info["progress_msg"]:
|
108 |
+
cls.model.update(progress_msg=cls.model.progress_msg + "\n" + info["progress_msg"]).where(
|
109 |
+
cls.model.id == id).execute()
|
110 |
+
if "progress" in info:
|
111 |
+
cls.model.update(progress=info["progress"]).where(
|
112 |
+
cls.model.id == id).execute()
|
113 |
+
return
|
114 |
+
|
115 |
with DB.lock("update_progress", -1):
|
116 |
if info["progress_msg"]:
|
117 |
cls.model.update(progress_msg=cls.model.progress_msg + "\n" + info["progress_msg"]).where(
|
docker/docker-compose-CN-oc9.yml
CHANGED
@@ -24,6 +24,7 @@ services:
|
|
24 |
environment:
|
25 |
- TZ=${TIMEZONE}
|
26 |
- HF_ENDPOINT=https://hf-mirror.com
|
|
|
27 |
networks:
|
28 |
- ragflow
|
29 |
restart: always
|
|
|
24 |
environment:
|
25 |
- TZ=${TIMEZONE}
|
26 |
- HF_ENDPOINT=https://hf-mirror.com
|
27 |
+
- MACOS=${MACOS}
|
28 |
networks:
|
29 |
- ragflow
|
30 |
restart: always
|
docker/docker-compose-CN.yml
CHANGED
@@ -24,6 +24,7 @@ services:
|
|
24 |
environment:
|
25 |
- TZ=${TIMEZONE}
|
26 |
- HF_ENDPOINT=https://hf-mirror.com
|
|
|
27 |
networks:
|
28 |
- ragflow
|
29 |
restart: always
|
|
|
24 |
environment:
|
25 |
- TZ=${TIMEZONE}
|
26 |
- HF_ENDPOINT=https://hf-mirror.com
|
27 |
+
- MACOS=${MACOS}
|
28 |
networks:
|
29 |
- ragflow
|
30 |
restart: always
|
docker/docker-compose.yml
CHANGED
@@ -24,6 +24,7 @@ services:
|
|
24 |
environment:
|
25 |
- TZ=${TIMEZONE}
|
26 |
- HF_ENDPOINT=https://huggingface.co
|
|
|
27 |
networks:
|
28 |
- ragflow
|
29 |
restart: always
|
|
|
24 |
environment:
|
25 |
- TZ=${TIMEZONE}
|
26 |
- HF_ENDPOINT=https://huggingface.co
|
27 |
+
- MACOS=${MACOS}
|
28 |
networks:
|
29 |
- ragflow
|
30 |
restart: always
|
rag/app/picture.py
CHANGED
@@ -24,11 +24,6 @@ ocr = OCR()
|
|
24 |
|
25 |
|
26 |
def chunk(filename, binary, tenant_id, lang, callback=None, **kwargs):
|
27 |
-
try:
|
28 |
-
cv_mdl = LLMBundle(tenant_id, LLMType.IMAGE2TEXT, lang=lang)
|
29 |
-
except Exception as e:
|
30 |
-
callback(prog=-1, msg=str(e))
|
31 |
-
return []
|
32 |
img = Image.open(io.BytesIO(binary)).convert('RGB')
|
33 |
doc = {
|
34 |
"docnm_kwd": filename,
|
@@ -45,6 +40,7 @@ def chunk(filename, binary, tenant_id, lang, callback=None, **kwargs):
|
|
45 |
|
46 |
try:
|
47 |
callback(0.4, "Use CV LLM to describe the picture.")
|
|
|
48 |
ans = cv_mdl.describe(binary)
|
49 |
callback(0.8, "CV LLM respoond: %s ..." % ans[:32])
|
50 |
txt += "\n" + ans
|
|
|
24 |
|
25 |
|
26 |
def chunk(filename, binary, tenant_id, lang, callback=None, **kwargs):
|
|
|
|
|
|
|
|
|
|
|
27 |
img = Image.open(io.BytesIO(binary)).convert('RGB')
|
28 |
doc = {
|
29 |
"docnm_kwd": filename,
|
|
|
40 |
|
41 |
try:
|
42 |
callback(0.4, "Use CV LLM to describe the picture.")
|
43 |
+
cv_mdl = LLMBundle(tenant_id, LLMType.IMAGE2TEXT, lang=lang)
|
44 |
ans = cv_mdl.describe(binary)
|
45 |
callback(0.8, "CV LLM respoond: %s ..." % ans[:32])
|
46 |
txt += "\n" + ans
|
rag/llm/cv_model.py
CHANGED
@@ -78,7 +78,7 @@ class GptV4(Base):
|
|
78 |
prompt = self.prompt(b64)
|
79 |
for i in range(len(prompt)):
|
80 |
for c in prompt[i]["content"]:
|
81 |
-
if "
|
82 |
|
83 |
res = self.client.chat.completions.create(
|
84 |
model=self.model_name,
|
|
|
78 |
prompt = self.prompt(b64)
|
79 |
for i in range(len(prompt)):
|
80 |
for c in prompt[i]["content"]:
|
81 |
+
if "text" in c: c["type"] = "text"
|
82 |
|
83 |
res = self.client.chat.completions.create(
|
84 |
model=self.model_name,
|
rag/llm/embedding_model.py
CHANGED
@@ -15,7 +15,6 @@
|
|
15 |
#
|
16 |
import re
|
17 |
from typing import Optional
|
18 |
-
|
19 |
import requests
|
20 |
from huggingface_hub import snapshot_download
|
21 |
from zhipuai import ZhipuAI
|
@@ -344,4 +343,4 @@ class InfinityEmbed(Base):
|
|
344 |
def encode_queries(self, text: str) -> tuple[np.ndarray, int]:
|
345 |
# Using the internal tokenizer to encode the texts and get the total
|
346 |
# number of tokens
|
347 |
-
return self.encode([text])
|
|
|
15 |
#
|
16 |
import re
|
17 |
from typing import Optional
|
|
|
18 |
import requests
|
19 |
from huggingface_hub import snapshot_download
|
20 |
from zhipuai import ZhipuAI
|
|
|
343 |
def encode_queries(self, text: str) -> tuple[np.ndarray, int]:
|
344 |
# Using the internal tokenizer to encode the texts and get the total
|
345 |
# number of tokens
|
346 |
+
return self.encode([text])
|