KevinHuSh commited on
Commit
484e5ab
·
1 Parent(s): f3dd131

llm configuation refine and trievalTest API refine (#40)

Browse files
api/apps/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/apps/chunk_app.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -13,6 +13,7 @@
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
 
16
 
17
  from flask import request
18
  from flask_login import login_required, current_user
@@ -177,6 +178,7 @@ def create():
177
  d["content_sm_ltks"] = huqie.qieqie(d["content_ltks"])
178
  d["important_kwd"] = req.get("important_kwd", [])
179
  d["important_tks"] = huqie.qie(" ".join(req.get("important_kwd", [])))
 
180
 
181
  try:
182
  e, doc = DocumentService.get_by_id(req["doc_id"])
@@ -223,7 +225,7 @@ def retrieval_test():
223
  embd_mdl = TenantLLMService.model_instance(
224
  kb.tenant_id, LLMType.EMBEDDING.value)
225
  ranks = retrievaler.retrieval(question, embd_mdl, kb.tenant_id, [kb_id], page, size, similarity_threshold,
226
- vector_similarity_weight, top, doc_ids)
227
 
228
  return get_json_result(data=ranks)
229
  except Exception as e:
@@ -231,4 +233,3 @@ def retrieval_test():
231
  return get_json_result(data=False, retmsg=f'Index not found!',
232
  retcode=RetCode.DATA_ERROR)
233
  return server_error_response(e)
234
-
 
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.
 
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
16
+ import datetime
17
 
18
  from flask import request
19
  from flask_login import login_required, current_user
 
178
  d["content_sm_ltks"] = huqie.qieqie(d["content_ltks"])
179
  d["important_kwd"] = req.get("important_kwd", [])
180
  d["important_tks"] = huqie.qie(" ".join(req.get("important_kwd", [])))
181
+ d["create_time"] = str(datetime.datetime.now()).replace("T", " ")[:19]
182
 
183
  try:
184
  e, doc = DocumentService.get_by_id(req["doc_id"])
 
225
  embd_mdl = TenantLLMService.model_instance(
226
  kb.tenant_id, LLMType.EMBEDDING.value)
227
  ranks = retrievaler.retrieval(question, embd_mdl, kb.tenant_id, [kb_id], page, size, similarity_threshold,
228
+ vector_similarity_weight, top, doc_ids)
229
 
230
  return get_json_result(data=ranks)
231
  except Exception as e:
 
233
  return get_json_result(data=False, retmsg=f'Index not found!',
234
  retcode=RetCode.DATA_ERROR)
235
  return server_error_response(e)
 
api/apps/conversation_app.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -13,22 +13,16 @@
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
16
- import re
17
-
18
- import tiktoken
19
  from flask import request
20
- from flask_login import login_required, current_user
21
  from api.db.services.dialog_service import DialogService, ConversationService
22
- from api.db import StatusEnum, LLMType
23
- from api.db.services.kb_service import KnowledgebaseService
24
  from api.db.services.llm_service import LLMService, TenantLLMService
25
- from api.db.services.user_service import TenantService
26
  from api.utils.api_utils import server_error_response, get_data_error_result, validate_request
27
  from api.utils import get_uuid
28
  from api.utils.api_utils import get_json_result
29
  from rag.llm import ChatModel
30
  from rag.nlp import retrievaler
31
- from rag.nlp.query import EsQueryer
32
  from rag.utils import num_tokens_from_string, encoder
33
 
34
 
@@ -142,6 +136,27 @@ def message_fit_in(msg, max_length=4000):
142
  return max_length, msg
143
 
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  def chat(dialog, messages, **kwargs):
146
  assert messages[-1]["role"] == "user", "The last content of this conversation is not from user."
147
  llm = LLMService.query(llm_name=dialog.llm_id)
@@ -156,7 +171,7 @@ def chat(dialog, messages, **kwargs):
156
  prompt_config["system"] = prompt_config["system"].replace("{%s}"%p["key"], " ")
157
 
158
  model_config = TenantLLMService.get_api_key(dialog.tenant_id, LLMType.CHAT.value, dialog.llm_id)
159
- if not model_config: raise LookupError("LLM(%s) API key not found"%dialog.llm_id)
160
 
161
  question = messages[-1]["content"]
162
  embd_mdl = TenantLLMService.model_instance(
@@ -183,25 +198,4 @@ def chat(dialog, messages, **kwargs):
183
  embd_mdl,
184
  tkweight=1-dialog.vector_similarity_weight,
185
  vtweight=dialog.vector_similarity_weight)
186
- return {"answer": answer, "retrieval": kbinfos}
187
-
188
-
189
- @manager.route('/completion', methods=['POST'])
190
- @login_required
191
- @validate_request("dialog_id", "messages")
192
- def completion():
193
- req = request.json
194
- msg = []
195
- for m in req["messages"]:
196
- if m["role"] == "system":continue
197
- if m["role"] == "assistant" and not msg:continue
198
- msg.append({"role": m["role"], "content": m["content"]})
199
- try:
200
- e, dia = DialogService.get_by_id(req["dialog_id"])
201
- if not e:
202
- return get_data_error_result(retmsg="Dialog not found!")
203
- del req["dialog_id"]
204
- del req["messages"]
205
- return get_json_result(data=chat(dia, msg, **req))
206
- except Exception as e:
207
- return server_error_response(e)
 
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.
 
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
 
 
 
16
  from flask import request
17
+ from flask_login import login_required
18
  from api.db.services.dialog_service import DialogService, ConversationService
19
+ from api.db import LLMType
 
20
  from api.db.services.llm_service import LLMService, TenantLLMService
 
21
  from api.utils.api_utils import server_error_response, get_data_error_result, validate_request
22
  from api.utils import get_uuid
23
  from api.utils.api_utils import get_json_result
24
  from rag.llm import ChatModel
25
  from rag.nlp import retrievaler
 
26
  from rag.utils import num_tokens_from_string, encoder
27
 
28
 
 
136
  return max_length, msg
137
 
138
 
139
+ @manager.route('/completion', methods=['POST'])
140
+ @login_required
141
+ @validate_request("dialog_id", "messages")
142
+ def completion():
143
+ req = request.json
144
+ msg = []
145
+ for m in req["messages"]:
146
+ if m["role"] == "system":continue
147
+ if m["role"] == "assistant" and not msg:continue
148
+ msg.append({"role": m["role"], "content": m["content"]})
149
+ try:
150
+ e, dia = DialogService.get_by_id(req["dialog_id"])
151
+ if not e:
152
+ return get_data_error_result(retmsg="Dialog not found!")
153
+ del req["dialog_id"]
154
+ del req["messages"]
155
+ return get_json_result(data=chat(dia, msg, **req))
156
+ except Exception as e:
157
+ return server_error_response(e)
158
+
159
+
160
  def chat(dialog, messages, **kwargs):
161
  assert messages[-1]["role"] == "user", "The last content of this conversation is not from user."
162
  llm = LLMService.query(llm_name=dialog.llm_id)
 
171
  prompt_config["system"] = prompt_config["system"].replace("{%s}"%p["key"], " ")
172
 
173
  model_config = TenantLLMService.get_api_key(dialog.tenant_id, LLMType.CHAT.value, dialog.llm_id)
174
+ if not model_config: raise LookupError("LLM({}) API key not found".format(dialog.llm_id))
175
 
176
  question = messages[-1]["content"]
177
  embd_mdl = TenantLLMService.model_instance(
 
198
  embd_mdl,
199
  tkweight=1-dialog.vector_similarity_weight,
200
  vtweight=dialog.vector_similarity_weight)
201
+ return {"answer": answer, "retrieval": kbinfos}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
api/apps/dialog_app.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/apps/document_app.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/apps/kb_app.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/apps/llm_app.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -71,18 +71,12 @@ def my_llms():
71
  def list():
72
  try:
73
  objs = TenantLLMService.query(tenant_id=current_user.id)
74
- objs = [o.to_dict() for o in objs if o.api_key]
75
- fct = {}
76
- for o in objs:
77
- if o["llm_factory"] not in fct: fct[o["llm_factory"]] = []
78
- if o["llm_name"]: fct[o["llm_factory"]].append(o["llm_name"])
79
-
80
  llms = LLMService.get_all()
81
  llms = [m.to_dict() for m in llms if m.status == StatusEnum.VALID.value]
82
  for m in llms:
83
- m["available"] = False
84
- if m["fid"] in fct and (not fct[m["fid"]] or m["llm_name"] in fct[m["fid"]]):
85
- m["available"] = True
86
  res = {}
87
  for m in llms:
88
  if m["fid"] not in res: res[m["fid"]] = []
 
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.
 
71
  def list():
72
  try:
73
  objs = TenantLLMService.query(tenant_id=current_user.id)
74
+ mdlnms = set([o.to_dict()["llm_name"] for o in objs if o.api_key])
 
 
 
 
 
75
  llms = LLMService.get_all()
76
  llms = [m.to_dict() for m in llms if m.status == StatusEnum.VALID.value]
77
  for m in llms:
78
+ m["available"] = m.llm_name in mdlnms
79
+
 
80
  res = {}
81
  for m in llms:
82
  if m["fid"] not in res: res[m["fid"]] = []
api/apps/user_app.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -13,12 +13,14 @@
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
 
 
16
  from flask import request, session, redirect, url_for
17
  from werkzeug.security import generate_password_hash, check_password_hash
18
  from flask_login import login_required, current_user, login_user, logout_user
19
 
20
  from api.db.db_models import TenantLLM
21
- from api.db.services.llm_service import TenantLLMService
22
  from api.utils.api_utils import server_error_response, validate_request
23
  from api.utils import get_uuid, get_format_time, decrypt, download_img
24
  from api.db import UserTenantRole, LLMType
@@ -185,8 +187,6 @@ def rollback_user_registration(user_id):
185
 
186
 
187
  def user_register(user_id, user):
188
-
189
- user_id = get_uuid()
190
  user["id"] = user_id
191
  tenant = {
192
  "id": user_id,
@@ -203,12 +203,14 @@ def user_register(user_id, user):
203
  "invited_by": user_id,
204
  "role": UserTenantRole.OWNER
205
  }
206
- tenant_llm = {"tenant_id": user_id, "llm_factory": "OpenAI", "api_key": "infiniflow API Key"}
 
 
207
 
208
  if not UserService.save(**user):return
209
  TenantService.save(**tenant)
210
  UserTenantService.save(**usr_tenant)
211
- TenantLLMService.save(**tenant_llm)
212
  return UserService.query(email=user["email"])
213
 
214
 
@@ -218,6 +220,9 @@ def user_add():
218
  req = request.json
219
  if UserService.query(email=req["email"]):
220
  return get_json_result(data=False, retmsg=f'Email: {req["email"]} has already registered!', retcode=RetCode.OPERATING_ERROR)
 
 
 
221
 
222
  user_dict = {
223
  "access_token": get_uuid(),
 
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.
 
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
16
+ import re
17
+
18
  from flask import request, session, redirect, url_for
19
  from werkzeug.security import generate_password_hash, check_password_hash
20
  from flask_login import login_required, current_user, login_user, logout_user
21
 
22
  from api.db.db_models import TenantLLM
23
+ from api.db.services.llm_service import TenantLLMService, LLMService
24
  from api.utils.api_utils import server_error_response, validate_request
25
  from api.utils import get_uuid, get_format_time, decrypt, download_img
26
  from api.db import UserTenantRole, LLMType
 
187
 
188
 
189
  def user_register(user_id, user):
 
 
190
  user["id"] = user_id
191
  tenant = {
192
  "id": user_id,
 
203
  "invited_by": user_id,
204
  "role": UserTenantRole.OWNER
205
  }
206
+ tenant_llm = []
207
+ for llm in LLMService.query(fid="Infiniflow"):
208
+ tenant_llm.append({"tenant_id": user_id, "llm_factory": "Infiniflow", "llm_name": llm.llm_name, "model_type":llm.model_type, "api_key": "infiniflow API Key"})
209
 
210
  if not UserService.save(**user):return
211
  TenantService.save(**tenant)
212
  UserTenantService.save(**usr_tenant)
213
+ TenantLLMService.insert_many(tenant_llm)
214
  return UserService.query(email=user["email"])
215
 
216
 
 
220
  req = request.json
221
  if UserService.query(email=req["email"]):
222
  return get_json_result(data=False, retmsg=f'Email: {req["email"]} has already registered!', retcode=RetCode.OPERATING_ERROR)
223
+ if not re.match(r"^[\w\._-]+@([\w_-]+\.)+[\w-]{2,4}$", req["email"]):
224
+ return get_json_result(data=False, retmsg=f'Invaliad e-mail: {req["email"]}!',
225
+ retcode=RetCode.OPERATING_ERROR)
226
 
227
  user_dict = {
228
  "access_token": get_uuid(),
api/db/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/db_models.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -426,8 +426,8 @@ class LLMFactories(DataBaseModel):
426
 
427
 
428
  class LLM(DataBaseModel):
429
- # defautlt LLMs for every users
430
- llm_name = CharField(max_length=128, null=False, help_text="LLM name", primary_key=True)
431
  model_type = CharField(max_length=128, null=False, help_text="LLM, Text Embedding, Image2Text, ASR")
432
  fid = CharField(max_length=128, null=False, help_text="LLM factory id")
433
  max_tokens = IntegerField(default=0)
@@ -448,6 +448,7 @@ class TenantLLM(DataBaseModel):
448
  llm_name = CharField(max_length=128, null=True, help_text="LLM name", default="")
449
  api_key = CharField(max_length=255, null=True, help_text="API KEY")
450
  api_base = CharField(max_length=255, null=True, help_text="API Base")
 
451
 
452
  def __str__(self):
453
  return self.llm_name
@@ -468,8 +469,8 @@ class Knowledgebase(DataBaseModel):
468
  doc_num = IntegerField(default=0)
469
  token_num = IntegerField(default=0)
470
  chunk_num = IntegerField(default=0)
471
- #similarity_threshold = FloatField(default=0.4)
472
- #vector_similarity_weight = FloatField(default=0.3)
473
 
474
  parser_id = CharField(max_length=32, null=False, help_text="default parser ID")
475
  status = CharField(max_length=1, null=True, help_text="is it validate(0: wasted,1: validate)", default="1")
 
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.
 
426
 
427
 
428
  class LLM(DataBaseModel):
429
+ # LLMs dictionary
430
+ llm_name = CharField(max_length=128, null=False, help_text="LLM name", index=True)
431
  model_type = CharField(max_length=128, null=False, help_text="LLM, Text Embedding, Image2Text, ASR")
432
  fid = CharField(max_length=128, null=False, help_text="LLM factory id")
433
  max_tokens = IntegerField(default=0)
 
448
  llm_name = CharField(max_length=128, null=True, help_text="LLM name", default="")
449
  api_key = CharField(max_length=255, null=True, help_text="API KEY")
450
  api_base = CharField(max_length=255, null=True, help_text="API Base")
451
+ used_tokens = IntegerField(default=0)
452
 
453
  def __str__(self):
454
  return self.llm_name
 
469
  doc_num = IntegerField(default=0)
470
  token_num = IntegerField(default=0)
471
  chunk_num = IntegerField(default=0)
472
+ similarity_threshold = FloatField(default=0.4)
473
+ vector_similarity_weight = FloatField(default=0.3)
474
 
475
  parser_id = CharField(max_length=32, null=False, help_text="default parser ID")
476
  status = CharField(max_length=1, null=True, help_text="is it validate(0: wasted,1: validate)", default="1")
api/db/db_utils.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/init_data.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -46,6 +46,11 @@ def init_llm_factory():
46
  "logo": "",
47
  "tags": "LLM,TEXT EMBEDDING,SPEECH2TEXT,MODERATION",
48
  "status": "1",
 
 
 
 
 
49
  },{
50
  "name": "智普AI",
51
  "logo": "",
@@ -130,6 +135,30 @@ def init_llm_factory():
130
  "tags": "LLM,CHAT,IMAGE2TEXT",
131
  "max_tokens": 765,
132
  "model_type": LLMType.IMAGE2TEXT.value
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  },
134
  ]
135
  for info in factory_infos:
 
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.
 
46
  "logo": "",
47
  "tags": "LLM,TEXT EMBEDDING,SPEECH2TEXT,MODERATION",
48
  "status": "1",
49
+ },{
50
+ "name": "Infiniflow",
51
+ "logo": "",
52
+ "tags": "LLM,TEXT EMBEDDING,SPEECH2TEXT,MODERATION",
53
+ "status": "1",
54
  },{
55
  "name": "智普AI",
56
  "logo": "",
 
135
  "tags": "LLM,CHAT,IMAGE2TEXT",
136
  "max_tokens": 765,
137
  "model_type": LLMType.IMAGE2TEXT.value
138
+ },{
139
+ "fid": factory_infos[2]["name"],
140
+ "llm_name": "gpt-3.5-turbo",
141
+ "tags": "LLM,CHAT,4K",
142
+ "max_tokens": 4096,
143
+ "model_type": LLMType.CHAT.value
144
+ },{
145
+ "fid": factory_infos[2]["name"],
146
+ "llm_name": "text-embedding-ada-002",
147
+ "tags": "TEXT EMBEDDING,8K",
148
+ "max_tokens": 8191,
149
+ "model_type": LLMType.EMBEDDING.value
150
+ },{
151
+ "fid": factory_infos[2]["name"],
152
+ "llm_name": "whisper-1",
153
+ "tags": "SPEECH2TEXT",
154
+ "max_tokens": 25*1024*1024,
155
+ "model_type": LLMType.SPEECH2TEXT.value
156
+ },{
157
+ "fid": factory_infos[2]["name"],
158
+ "llm_name": "gpt-4-vision-preview",
159
+ "tags": "LLM,CHAT,IMAGE2TEXT",
160
+ "max_tokens": 765,
161
+ "model_type": LLMType.IMAGE2TEXT.value
162
  },
163
  ]
164
  for info in factory_infos:
api/db/operatioins.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/reload_config_base.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/runtime_config.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/services/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/services/common_service.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/services/dialog_service.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/services/document_service.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/services/kb_service.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/services/knowledgebase_service.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/db/services/llm_service.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -13,6 +13,7 @@
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
 
16
  from rag.llm import EmbeddingModel, CvModel
17
  from api.db import LLMType
18
  from api.db.db_models import DB, UserTenant
@@ -34,40 +35,39 @@ class TenantLLMService(CommonService):
34
 
35
  @classmethod
36
  @DB.connection_context()
37
- def get_api_key(cls, tenant_id, model_type, model_name=""):
38
- objs = cls.query(tenant_id=tenant_id, model_type=model_type)
39
- if objs and len(objs)>0 and objs[0].llm_name:
40
- return objs[0]
41
-
42
- fields = [LLM.llm_name, cls.model.llm_factory, cls.model.api_key]
43
- objs = cls.model.select(*fields).join(LLM, on=(LLM.fid == cls.model.llm_factory)).where(
44
- (cls.model.tenant_id == tenant_id),
45
- ((cls.model.model_type == model_type) | (cls.model.llm_name == model_name)),
46
- (LLM.status == StatusEnum.VALID)
47
- )
48
-
49
- if not objs:return
50
  return objs[0]
51
 
52
  @classmethod
53
  @DB.connection_context()
54
  def get_my_llms(cls, tenant_id):
55
  fields = [cls.model.llm_factory, LLMFactories.logo, LLMFactories.tags, cls.model.model_type, cls.model.llm_name]
56
- objs = cls.model.select(*fields).join(LLMFactories, on=(cls.model.llm_factory==LLMFactories.name)).where(cls.model.tenant_id==tenant_id).dicts()
 
57
 
58
  return list(objs)
59
 
60
  @classmethod
61
  @DB.connection_context()
62
  def model_instance(cls, tenant_id, llm_type):
63
- model_config = cls.get_api_key(tenant_id, model_type=LLMType.EMBEDDING.value)
64
- if not model_config:
65
- model_config = {"llm_factory": "local", "api_key": "", "llm_name": ""}
66
- else:
67
- model_config = model_config[0].to_dict()
68
- if llm_type == LLMType.EMBEDDING:
 
 
 
 
 
 
 
69
  if model_config["llm_factory"] not in EmbeddingModel: return
70
  return EmbeddingModel[model_config["llm_factory"]](model_config["api_key"], model_config["llm_name"])
71
- if llm_type == LLMType.IMAGE2TEXT:
 
72
  if model_config["llm_factory"] not in CvModel: return
73
- return CvModel[model_config.llm_factory](model_config["api_key"], model_config["llm_name"])
 
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.
 
13
  # See the License for the specific language governing permissions and
14
  # limitations under the License.
15
  #
16
+ from api.db.services.user_service import TenantService
17
  from rag.llm import EmbeddingModel, CvModel
18
  from api.db import LLMType
19
  from api.db.db_models import DB, UserTenant
 
35
 
36
  @classmethod
37
  @DB.connection_context()
38
+ def get_api_key(cls, tenant_id, model_name):
39
+ objs = cls.query(tenant_id=tenant_id, llm_name=model_name)
40
+ if not objs: return
 
 
 
 
 
 
 
 
 
 
41
  return objs[0]
42
 
43
  @classmethod
44
  @DB.connection_context()
45
  def get_my_llms(cls, tenant_id):
46
  fields = [cls.model.llm_factory, LLMFactories.logo, LLMFactories.tags, cls.model.model_type, cls.model.llm_name]
47
+ objs = cls.model.select(*fields).join(LLMFactories, on=(cls.model.llm_factory == LLMFactories.name)).where(
48
+ cls.model.tenant_id == tenant_id).dicts()
49
 
50
  return list(objs)
51
 
52
  @classmethod
53
  @DB.connection_context()
54
  def model_instance(cls, tenant_id, llm_type):
55
+ e,tenant = TenantService.get_by_id(tenant_id)
56
+ if not e: raise LookupError("Tenant not found")
57
+
58
+ if llm_type == LLMType.EMBEDDING.value: mdlnm = tenant.embd_id
59
+ elif llm_type == LLMType.SPEECH2TEXT.value: mdlnm = tenant.asr_id
60
+ elif llm_type == LLMType.IMAGE2TEXT.value: mdlnm = tenant.img2txt_id
61
+ elif llm_type == LLMType.CHAT.value: mdlnm = tenant.llm_id
62
+ else: assert False, "LLM type error"
63
+
64
+ model_config = cls.get_api_key(tenant_id, mdlnm)
65
+ if not model_config: raise LookupError("Model({}) not found".format(mdlnm))
66
+ model_config = model_config[0].to_dict()
67
+ if llm_type == LLMType.EMBEDDING.value:
68
  if model_config["llm_factory"] not in EmbeddingModel: return
69
  return EmbeddingModel[model_config["llm_factory"]](model_config["api_key"], model_config["llm_name"])
70
+
71
+ if llm_type == LLMType.IMAGE2TEXT.value:
72
  if model_config["llm_factory"] not in CvModel: return
73
+ return CvModel[model_config["llm_factory"]](model_config["api_key"], model_config["llm_name"])
api/db/services/user_service.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/errors/general_error.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/ragflow_server.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/settings.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/utils/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/utils/api_utils.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/utils/file_utils.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/utils/log_utils.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
api/versions.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
rag/llm/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -19,7 +19,7 @@ from .cv_model import *
19
 
20
 
21
  EmbeddingModel = {
22
- "local": HuEmbedding,
23
  "OpenAI": OpenAIEmbed,
24
  "通义千问": QWenEmbed,
25
  }
@@ -27,12 +27,14 @@ EmbeddingModel = {
27
 
28
  CvModel = {
29
  "OpenAI": GptV4,
 
30
  "通义千问": QWenCV,
31
  }
32
 
33
 
34
  ChatModel = {
35
  "OpenAI": GptTurbo,
 
36
  "通义千问": QWenChat,
37
  }
38
 
 
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.
 
19
 
20
 
21
  EmbeddingModel = {
22
+ "Infiniflow": HuEmbedding,
23
  "OpenAI": OpenAIEmbed,
24
  "通义千问": QWenEmbed,
25
  }
 
27
 
28
  CvModel = {
29
  "OpenAI": GptV4,
30
+ "Infiniflow": GptV4,
31
  "通义千问": QWenCV,
32
  }
33
 
34
 
35
  ChatModel = {
36
  "OpenAI": GptTurbo,
37
+ "Infiniflow": GptTurbo,
38
  "通义千问": QWenChat,
39
  }
40
 
rag/llm/chat_model.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
rag/llm/cv_model.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
rag/llm/embedding_model.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
@@ -24,6 +24,9 @@ import numpy as np
24
 
25
  from rag.utils import num_tokens_from_string
26
 
 
 
 
27
 
28
  class Base(ABC):
29
  def __init__(self, key, model_name):
@@ -47,9 +50,7 @@ class HuEmbedding(Base):
47
  ^_-
48
 
49
  """
50
- self.model = FlagModel("BAAI/bge-large-zh-v1.5",
51
- query_instruction_for_retrieval="为这个句子生成表示以用于检索相关文章:",
52
- use_fp16=torch.cuda.is_available())
53
 
54
 
55
  def encode(self, texts: list, batch_size=32):
 
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.
 
24
 
25
  from rag.utils import num_tokens_from_string
26
 
27
+ flag_model = FlagModel("BAAI/bge-large-zh-v1.5",
28
+ query_instruction_for_retrieval="为这个句子生成表示以用于检索相关文章:",
29
+ use_fp16=torch.cuda.is_available())
30
 
31
  class Base(ABC):
32
  def __init__(self, key, model_name):
 
50
  ^_-
51
 
52
  """
53
+ self.model = flag_model
 
 
54
 
55
 
56
  def encode(self, texts: list, batch_size=32):
rag/nlp/query.py CHANGED
@@ -42,7 +42,7 @@ class EsQueryer:
42
 
43
  def question(self, txt, tbl="qa", min_match="60%"):
44
  txt = re.sub(
45
- r"[ \t,,。??/`!!&]+",
46
  " ",
47
  huqie.tradi2simp(
48
  huqie.strQ2B(
 
42
 
43
  def question(self, txt, tbl="qa", min_match="60%"):
44
  txt = re.sub(
45
+ r"[ \r\n\t,,。??/`!!&]+",
46
  " ",
47
  huqie.tradi2simp(
48
  huqie.strQ2B(
rag/parser/pdf_parser.py CHANGED
@@ -1,4 +1,5 @@
1
  # -*- coding: utf-8 -*-
 
2
  import xgboost as xgb
3
  from io import BytesIO
4
  import torch
@@ -1527,8 +1528,6 @@ class HuParser:
1527
  return "\n\n".join(res)
1528
 
1529
  def __call__(self, fnm, need_image=True, zoomin=3, return_html=False):
1530
- self.pdf = pdfplumber.open(fnm) if isinstance(
1531
- fnm, str) else pdfplumber.open(BytesIO(fnm))
1532
  self.lefted_chars = []
1533
  self.mean_height = []
1534
  self.mean_width = []
@@ -1536,13 +1535,26 @@ class HuParser:
1536
  self.garbages = {}
1537
  self.page_cum_height = [0]
1538
  self.page_layout = []
1539
- self.page_images = [p.to_image(
1540
- resolution=72 * zoomin).annotated for i, p in enumerate(self.pdf.pages[:299])]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1541
  logging.info("Images converted.")
1542
- logging.info("Table processed.")
1543
 
1544
  for i, img in enumerate(self.page_images):
1545
- chars = [c for c in self.pdf.pages[i].chars if self._has_color(c)]
1546
  self.mean_height.append(
1547
  np.median(sorted([c["height"] for c in chars])) if chars else 0
1548
  )
 
1
  # -*- coding: utf-8 -*-
2
+ import fitz
3
  import xgboost as xgb
4
  from io import BytesIO
5
  import torch
 
1528
  return "\n\n".join(res)
1529
 
1530
  def __call__(self, fnm, need_image=True, zoomin=3, return_html=False):
 
 
1531
  self.lefted_chars = []
1532
  self.mean_height = []
1533
  self.mean_width = []
 
1535
  self.garbages = {}
1536
  self.page_cum_height = [0]
1537
  self.page_layout = []
1538
+ try:
1539
+ self.pdf = pdfplumber.open(fnm) if isinstance(fnm, str) else pdfplumber.open(BytesIO(fnm))
1540
+ self.page_images = [p.to_image(resolution=72*zoomin).annotated for i,p in enumerate(self.pdf.pages[:299])]
1541
+ self.page_chars = [[c for c in self.pdf.pages[i].chars if self._has_color(c)] for i in range(len(self.page_images))]
1542
+ except Exception as e:
1543
+ self.pdf = fitz.open(fnm) if isinstance(fnm, str) else fitz.open(stream=fnm, filetype="pdf")
1544
+ self.page_images = []
1545
+ self.page_chars = []
1546
+ mat = fitz.Matrix(zoomin, zoomin)
1547
+ for page in self.pdf:
1548
+ pix = page.getPixmap(matrix = mat)
1549
+ img = Image.frombytes("RGB", [pix.width, pix.height],
1550
+ pix.samples)
1551
+ self.page_images.append(img)
1552
+ self.page_chars.append([])
1553
+
1554
  logging.info("Images converted.")
 
1555
 
1556
  for i, img in enumerate(self.page_images):
1557
+ chars = self.page_chars[i]
1558
  self.mean_height.append(
1559
  np.median(sorted([c["height"] for c in chars])) if chars else 0
1560
  )
rag/settings.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.
rag/svr/parse_user_docs.py CHANGED
@@ -1,5 +1,5 @@
1
  #
2
- # Copyright 2019 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.
 
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.