model.py 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. import json
  2. import uuid
  3. from flask import current_app, request
  4. from flask_login import UserMixin
  5. from sqlalchemy import Float, text
  6. from sqlalchemy.dialects.postgresql import UUID
  7. from core.file.tool_file_parser import ToolFileParser
  8. from core.file.upload_file_parser import UploadFileParser
  9. from extensions.ext_database import db
  10. from libs.helper import generate_string
  11. from .account import Account, Tenant
  12. class DifySetup(db.Model):
  13. __tablename__ = 'dify_setups'
  14. __table_args__ = (
  15. db.PrimaryKeyConstraint('version', name='dify_setup_pkey'),
  16. )
  17. version = db.Column(db.String(255), nullable=False)
  18. setup_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  19. class App(db.Model):
  20. __tablename__ = 'apps'
  21. __table_args__ = (
  22. db.PrimaryKeyConstraint('id', name='app_pkey'),
  23. db.Index('app_tenant_id_idx', 'tenant_id')
  24. )
  25. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  26. tenant_id = db.Column(UUID, nullable=False)
  27. name = db.Column(db.String(255), nullable=False)
  28. mode = db.Column(db.String(255), nullable=False)
  29. icon = db.Column(db.String(255))
  30. icon_background = db.Column(db.String(255))
  31. app_model_config_id = db.Column(UUID, nullable=True)
  32. status = db.Column(db.String(255), nullable=False, server_default=db.text("'normal'::character varying"))
  33. enable_site = db.Column(db.Boolean, nullable=False)
  34. enable_api = db.Column(db.Boolean, nullable=False)
  35. api_rpm = db.Column(db.Integer, nullable=False)
  36. api_rph = db.Column(db.Integer, nullable=False)
  37. is_demo = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  38. is_public = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  39. is_universal = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  40. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  41. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  42. @property
  43. def site(self):
  44. site = db.session.query(Site).filter(Site.app_id == self.id).first()
  45. return site
  46. @property
  47. def app_model_config(self):
  48. app_model_config = db.session.query(AppModelConfig).filter(
  49. AppModelConfig.id == self.app_model_config_id).first()
  50. return app_model_config
  51. @property
  52. def api_base_url(self):
  53. return (current_app.config['SERVICE_API_URL'] if current_app.config['SERVICE_API_URL']
  54. else request.host_url.rstrip('/')) + '/v1'
  55. @property
  56. def tenant(self):
  57. tenant = db.session.query(Tenant).filter(Tenant.id == self.tenant_id).first()
  58. return tenant
  59. @property
  60. def is_agent(self) -> bool:
  61. app_model_config = self.app_model_config
  62. if not app_model_config:
  63. return False
  64. if not app_model_config.agent_mode:
  65. return False
  66. if self.app_model_config.agent_mode_dict.get('enabled', False) \
  67. and self.app_model_config.agent_mode_dict.get('strategy', '') in ['function_call', 'react']:
  68. return True
  69. return False
  70. @property
  71. def deleted_tools(self) -> list:
  72. # get agent mode tools
  73. app_model_config = self.app_model_config
  74. if not app_model_config:
  75. return []
  76. if not app_model_config.agent_mode:
  77. return []
  78. agent_mode = app_model_config.agent_mode_dict
  79. tools = agent_mode.get('tools', [])
  80. provider_ids = []
  81. for tool in tools:
  82. keys = list(tool.keys())
  83. if len(keys) >= 4:
  84. provider_type = tool.get('provider_type', '')
  85. provider_id = tool.get('provider_id', '')
  86. if provider_type == 'api':
  87. # check if provider id is a uuid string, if not, skip
  88. try:
  89. uuid.UUID(provider_id)
  90. except Exception:
  91. continue
  92. provider_ids.append(provider_id)
  93. if not provider_ids:
  94. return []
  95. api_providers = db.session.execute(
  96. text('SELECT id FROM tool_api_providers WHERE id IN :provider_ids'),
  97. {'provider_ids': tuple(provider_ids)}
  98. ).fetchall()
  99. deleted_tools = []
  100. current_api_provider_ids = [str(api_provider.id) for api_provider in api_providers]
  101. for tool in tools:
  102. keys = list(tool.keys())
  103. if len(keys) >= 4:
  104. provider_type = tool.get('provider_type', '')
  105. provider_id = tool.get('provider_id', '')
  106. if provider_type == 'api' and provider_id not in current_api_provider_ids:
  107. deleted_tools.append(tool['tool_name'])
  108. return deleted_tools
  109. class AppModelConfig(db.Model):
  110. __tablename__ = 'app_model_configs'
  111. __table_args__ = (
  112. db.PrimaryKeyConstraint('id', name='app_model_config_pkey'),
  113. db.Index('app_app_id_idx', 'app_id')
  114. )
  115. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  116. app_id = db.Column(UUID, nullable=False)
  117. provider = db.Column(db.String(255), nullable=False)
  118. model_id = db.Column(db.String(255), nullable=False)
  119. configs = db.Column(db.JSON, nullable=False)
  120. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  121. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  122. opening_statement = db.Column(db.Text)
  123. suggested_questions = db.Column(db.Text)
  124. suggested_questions_after_answer = db.Column(db.Text)
  125. speech_to_text = db.Column(db.Text)
  126. text_to_speech = db.Column(db.Text)
  127. more_like_this = db.Column(db.Text)
  128. model = db.Column(db.Text)
  129. user_input_form = db.Column(db.Text)
  130. dataset_query_variable = db.Column(db.String(255))
  131. pre_prompt = db.Column(db.Text)
  132. agent_mode = db.Column(db.Text)
  133. sensitive_word_avoidance = db.Column(db.Text)
  134. retriever_resource = db.Column(db.Text)
  135. prompt_type = db.Column(db.String(255), nullable=False, default='simple')
  136. chat_prompt_config = db.Column(db.Text)
  137. completion_prompt_config = db.Column(db.Text)
  138. dataset_configs = db.Column(db.Text)
  139. external_data_tools = db.Column(db.Text)
  140. file_upload = db.Column(db.Text)
  141. @property
  142. def app(self):
  143. app = db.session.query(App).filter(App.id == self.app_id).first()
  144. return app
  145. @property
  146. def model_dict(self) -> dict:
  147. return json.loads(self.model) if self.model else None
  148. @property
  149. def suggested_questions_list(self) -> list:
  150. return json.loads(self.suggested_questions) if self.suggested_questions else []
  151. @property
  152. def suggested_questions_after_answer_dict(self) -> dict:
  153. return json.loads(self.suggested_questions_after_answer) if self.suggested_questions_after_answer \
  154. else {"enabled": False}
  155. @property
  156. def speech_to_text_dict(self) -> dict:
  157. return json.loads(self.speech_to_text) if self.speech_to_text \
  158. else {"enabled": False}
  159. @property
  160. def text_to_speech_dict(self) -> dict:
  161. return json.loads(self.text_to_speech) if self.text_to_speech \
  162. else {"enabled": False}
  163. @property
  164. def retriever_resource_dict(self) -> dict:
  165. return json.loads(self.retriever_resource) if self.retriever_resource \
  166. else {"enabled": False}
  167. @property
  168. def annotation_reply_dict(self) -> dict:
  169. annotation_setting = db.session.query(AppAnnotationSetting).filter(
  170. AppAnnotationSetting.app_id == self.app_id).first()
  171. if annotation_setting:
  172. collection_binding_detail = annotation_setting.collection_binding_detail
  173. return {
  174. "id": annotation_setting.id,
  175. "enabled": True,
  176. "score_threshold": annotation_setting.score_threshold,
  177. "embedding_model": {
  178. "embedding_provider_name": collection_binding_detail.provider_name,
  179. "embedding_model_name": collection_binding_detail.model_name
  180. }
  181. }
  182. else:
  183. return {"enabled": False}
  184. @property
  185. def more_like_this_dict(self) -> dict:
  186. return json.loads(self.more_like_this) if self.more_like_this else {"enabled": False}
  187. @property
  188. def sensitive_word_avoidance_dict(self) -> dict:
  189. return json.loads(self.sensitive_word_avoidance) if self.sensitive_word_avoidance \
  190. else {"enabled": False, "type": "", "configs": []}
  191. @property
  192. def external_data_tools_list(self) -> list[dict]:
  193. return json.loads(self.external_data_tools) if self.external_data_tools \
  194. else []
  195. @property
  196. def user_input_form_list(self) -> dict:
  197. return json.loads(self.user_input_form) if self.user_input_form else []
  198. @property
  199. def agent_mode_dict(self) -> dict:
  200. return json.loads(self.agent_mode) if self.agent_mode else {"enabled": False, "strategy": None, "tools": [], "prompt": None}
  201. @property
  202. def chat_prompt_config_dict(self) -> dict:
  203. return json.loads(self.chat_prompt_config) if self.chat_prompt_config else {}
  204. @property
  205. def completion_prompt_config_dict(self) -> dict:
  206. return json.loads(self.completion_prompt_config) if self.completion_prompt_config else {}
  207. @property
  208. def dataset_configs_dict(self) -> dict:
  209. if self.dataset_configs:
  210. dataset_configs = json.loads(self.dataset_configs)
  211. if 'retrieval_model' not in dataset_configs:
  212. return {'retrieval_model': 'single'}
  213. else:
  214. return dataset_configs
  215. return {'retrieval_model': 'single'}
  216. @property
  217. def file_upload_dict(self) -> dict:
  218. return json.loads(self.file_upload) if self.file_upload else {
  219. "image": {"enabled": False, "number_limits": 3, "detail": "high",
  220. "transfer_methods": ["remote_url", "local_file"]}}
  221. def to_dict(self) -> dict:
  222. return {
  223. "provider": "",
  224. "model_id": "",
  225. "configs": {},
  226. "opening_statement": self.opening_statement,
  227. "suggested_questions": self.suggested_questions_list,
  228. "suggested_questions_after_answer": self.suggested_questions_after_answer_dict,
  229. "speech_to_text": self.speech_to_text_dict,
  230. "text_to_speech": self.text_to_speech_dict,
  231. "retriever_resource": self.retriever_resource_dict,
  232. "annotation_reply": self.annotation_reply_dict,
  233. "more_like_this": self.more_like_this_dict,
  234. "sensitive_word_avoidance": self.sensitive_word_avoidance_dict,
  235. "external_data_tools": self.external_data_tools_list,
  236. "model": self.model_dict,
  237. "user_input_form": self.user_input_form_list,
  238. "dataset_query_variable": self.dataset_query_variable,
  239. "pre_prompt": self.pre_prompt,
  240. "agent_mode": self.agent_mode_dict,
  241. "prompt_type": self.prompt_type,
  242. "chat_prompt_config": self.chat_prompt_config_dict,
  243. "completion_prompt_config": self.completion_prompt_config_dict,
  244. "dataset_configs": self.dataset_configs_dict,
  245. "file_upload": self.file_upload_dict
  246. }
  247. def from_model_config_dict(self, model_config: dict):
  248. self.provider = ""
  249. self.model_id = ""
  250. self.configs = {}
  251. self.opening_statement = model_config['opening_statement']
  252. self.suggested_questions = json.dumps(model_config['suggested_questions'])
  253. self.suggested_questions_after_answer = json.dumps(model_config['suggested_questions_after_answer'])
  254. self.speech_to_text = json.dumps(model_config['speech_to_text']) \
  255. if model_config.get('speech_to_text') else None
  256. self.text_to_speech = json.dumps(model_config['text_to_speech']) \
  257. if model_config.get('text_to_speech') else None
  258. self.more_like_this = json.dumps(model_config['more_like_this'])
  259. self.sensitive_word_avoidance = json.dumps(model_config['sensitive_word_avoidance']) \
  260. if model_config.get('sensitive_word_avoidance') else None
  261. self.external_data_tools = json.dumps(model_config['external_data_tools']) \
  262. if model_config.get('external_data_tools') else None
  263. self.model = json.dumps(model_config['model'])
  264. self.user_input_form = json.dumps(model_config['user_input_form'])
  265. self.dataset_query_variable = model_config.get('dataset_query_variable')
  266. self.pre_prompt = model_config['pre_prompt']
  267. self.agent_mode = json.dumps(model_config['agent_mode'])
  268. self.retriever_resource = json.dumps(model_config['retriever_resource']) \
  269. if model_config.get('retriever_resource') else None
  270. self.prompt_type = model_config.get('prompt_type', 'simple')
  271. self.chat_prompt_config = json.dumps(model_config.get('chat_prompt_config')) \
  272. if model_config.get('chat_prompt_config') else None
  273. self.completion_prompt_config = json.dumps(model_config.get('completion_prompt_config')) \
  274. if model_config.get('completion_prompt_config') else None
  275. self.dataset_configs = json.dumps(model_config.get('dataset_configs')) \
  276. if model_config.get('dataset_configs') else None
  277. self.file_upload = json.dumps(model_config.get('file_upload')) \
  278. if model_config.get('file_upload') else None
  279. return self
  280. def copy(self):
  281. new_app_model_config = AppModelConfig(
  282. id=self.id,
  283. app_id=self.app_id,
  284. provider="",
  285. model_id="",
  286. configs={},
  287. opening_statement=self.opening_statement,
  288. suggested_questions=self.suggested_questions,
  289. suggested_questions_after_answer=self.suggested_questions_after_answer,
  290. speech_to_text=self.speech_to_text,
  291. text_to_speech=self.text_to_speech,
  292. more_like_this=self.more_like_this,
  293. sensitive_word_avoidance=self.sensitive_word_avoidance,
  294. external_data_tools=self.external_data_tools,
  295. model=self.model,
  296. user_input_form=self.user_input_form,
  297. dataset_query_variable=self.dataset_query_variable,
  298. pre_prompt=self.pre_prompt,
  299. agent_mode=self.agent_mode,
  300. retriever_resource=self.retriever_resource,
  301. prompt_type=self.prompt_type,
  302. chat_prompt_config=self.chat_prompt_config,
  303. completion_prompt_config=self.completion_prompt_config,
  304. dataset_configs=self.dataset_configs,
  305. file_upload=self.file_upload
  306. )
  307. return new_app_model_config
  308. class RecommendedApp(db.Model):
  309. __tablename__ = 'recommended_apps'
  310. __table_args__ = (
  311. db.PrimaryKeyConstraint('id', name='recommended_app_pkey'),
  312. db.Index('recommended_app_app_id_idx', 'app_id'),
  313. db.Index('recommended_app_is_listed_idx', 'is_listed', 'language')
  314. )
  315. id = db.Column(UUID, primary_key=True, server_default=db.text('uuid_generate_v4()'))
  316. app_id = db.Column(UUID, nullable=False)
  317. description = db.Column(db.JSON, nullable=False)
  318. copyright = db.Column(db.String(255), nullable=False)
  319. privacy_policy = db.Column(db.String(255), nullable=False)
  320. category = db.Column(db.String(255), nullable=False)
  321. position = db.Column(db.Integer, nullable=False, default=0)
  322. is_listed = db.Column(db.Boolean, nullable=False, default=True)
  323. install_count = db.Column(db.Integer, nullable=False, default=0)
  324. language = db.Column(db.String(255), nullable=False, server_default=db.text("'en-US'::character varying"))
  325. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  326. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  327. @property
  328. def app(self):
  329. app = db.session.query(App).filter(App.id == self.app_id).first()
  330. return app
  331. class InstalledApp(db.Model):
  332. __tablename__ = 'installed_apps'
  333. __table_args__ = (
  334. db.PrimaryKeyConstraint('id', name='installed_app_pkey'),
  335. db.Index('installed_app_tenant_id_idx', 'tenant_id'),
  336. db.Index('installed_app_app_id_idx', 'app_id'),
  337. db.UniqueConstraint('tenant_id', 'app_id', name='unique_tenant_app')
  338. )
  339. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  340. tenant_id = db.Column(UUID, nullable=False)
  341. app_id = db.Column(UUID, nullable=False)
  342. app_owner_tenant_id = db.Column(UUID, nullable=False)
  343. position = db.Column(db.Integer, nullable=False, default=0)
  344. is_pinned = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  345. last_used_at = db.Column(db.DateTime, nullable=True)
  346. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  347. @property
  348. def app(self):
  349. app = db.session.query(App).filter(App.id == self.app_id).first()
  350. return app
  351. @property
  352. def tenant(self):
  353. tenant = db.session.query(Tenant).filter(Tenant.id == self.tenant_id).first()
  354. return tenant
  355. @property
  356. def is_agent(self) -> bool:
  357. app = self.app
  358. if not app:
  359. return False
  360. return app.is_agent
  361. class Conversation(db.Model):
  362. __tablename__ = 'conversations'
  363. __table_args__ = (
  364. db.PrimaryKeyConstraint('id', name='conversation_pkey'),
  365. db.Index('conversation_app_from_user_idx', 'app_id', 'from_source', 'from_end_user_id')
  366. )
  367. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  368. app_id = db.Column(UUID, nullable=False)
  369. app_model_config_id = db.Column(UUID, nullable=False)
  370. model_provider = db.Column(db.String(255), nullable=False)
  371. override_model_configs = db.Column(db.Text)
  372. model_id = db.Column(db.String(255), nullable=False)
  373. mode = db.Column(db.String(255), nullable=False)
  374. name = db.Column(db.String(255), nullable=False)
  375. summary = db.Column(db.Text)
  376. inputs = db.Column(db.JSON)
  377. introduction = db.Column(db.Text)
  378. system_instruction = db.Column(db.Text)
  379. system_instruction_tokens = db.Column(db.Integer, nullable=False, server_default=db.text('0'))
  380. status = db.Column(db.String(255), nullable=False)
  381. from_source = db.Column(db.String(255), nullable=False)
  382. from_end_user_id = db.Column(UUID)
  383. from_account_id = db.Column(UUID)
  384. read_at = db.Column(db.DateTime)
  385. read_account_id = db.Column(UUID)
  386. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  387. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  388. messages = db.relationship("Message", backref="conversation", lazy='select', passive_deletes="all")
  389. message_annotations = db.relationship("MessageAnnotation", backref="conversation", lazy='select',
  390. passive_deletes="all")
  391. is_deleted = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  392. @property
  393. def model_config(self):
  394. model_config = {}
  395. if self.override_model_configs:
  396. override_model_configs = json.loads(self.override_model_configs)
  397. if 'model' in override_model_configs:
  398. app_model_config = AppModelConfig()
  399. app_model_config = app_model_config.from_model_config_dict(override_model_configs)
  400. model_config = app_model_config.to_dict()
  401. else:
  402. model_config['configs'] = override_model_configs
  403. else:
  404. app_model_config = db.session.query(AppModelConfig).filter(
  405. AppModelConfig.id == self.app_model_config_id).first()
  406. model_config = app_model_config.to_dict()
  407. model_config['model_id'] = self.model_id
  408. model_config['provider'] = self.model_provider
  409. return model_config
  410. @property
  411. def summary_or_query(self):
  412. if self.summary:
  413. return self.summary
  414. else:
  415. first_message = self.first_message
  416. if first_message:
  417. return first_message.query
  418. else:
  419. return ''
  420. @property
  421. def annotated(self):
  422. return db.session.query(MessageAnnotation).filter(MessageAnnotation.conversation_id == self.id).count() > 0
  423. @property
  424. def annotation(self):
  425. return db.session.query(MessageAnnotation).filter(MessageAnnotation.conversation_id == self.id).first()
  426. @property
  427. def message_count(self):
  428. return db.session.query(Message).filter(Message.conversation_id == self.id).count()
  429. @property
  430. def user_feedback_stats(self):
  431. like = db.session.query(MessageFeedback) \
  432. .filter(MessageFeedback.conversation_id == self.id,
  433. MessageFeedback.from_source == 'user',
  434. MessageFeedback.rating == 'like').count()
  435. dislike = db.session.query(MessageFeedback) \
  436. .filter(MessageFeedback.conversation_id == self.id,
  437. MessageFeedback.from_source == 'user',
  438. MessageFeedback.rating == 'dislike').count()
  439. return {'like': like, 'dislike': dislike}
  440. @property
  441. def admin_feedback_stats(self):
  442. like = db.session.query(MessageFeedback) \
  443. .filter(MessageFeedback.conversation_id == self.id,
  444. MessageFeedback.from_source == 'admin',
  445. MessageFeedback.rating == 'like').count()
  446. dislike = db.session.query(MessageFeedback) \
  447. .filter(MessageFeedback.conversation_id == self.id,
  448. MessageFeedback.from_source == 'admin',
  449. MessageFeedback.rating == 'dislike').count()
  450. return {'like': like, 'dislike': dislike}
  451. @property
  452. def first_message(self):
  453. return db.session.query(Message).filter(Message.conversation_id == self.id).first()
  454. @property
  455. def app(self):
  456. return db.session.query(App).filter(App.id == self.app_id).first()
  457. @property
  458. def from_end_user_session_id(self):
  459. if self.from_end_user_id:
  460. end_user = db.session.query(EndUser).filter(EndUser.id == self.from_end_user_id).first()
  461. if end_user:
  462. return end_user.session_id
  463. return None
  464. @property
  465. def in_debug_mode(self):
  466. return self.override_model_configs is not None
  467. class Message(db.Model):
  468. __tablename__ = 'messages'
  469. __table_args__ = (
  470. db.PrimaryKeyConstraint('id', name='message_pkey'),
  471. db.Index('message_app_id_idx', 'app_id', 'created_at'),
  472. db.Index('message_conversation_id_idx', 'conversation_id'),
  473. db.Index('message_end_user_idx', 'app_id', 'from_source', 'from_end_user_id'),
  474. db.Index('message_account_idx', 'app_id', 'from_source', 'from_account_id'),
  475. )
  476. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  477. app_id = db.Column(UUID, nullable=False)
  478. model_provider = db.Column(db.String(255), nullable=False)
  479. model_id = db.Column(db.String(255), nullable=False)
  480. override_model_configs = db.Column(db.Text)
  481. conversation_id = db.Column(UUID, db.ForeignKey('conversations.id'), nullable=False)
  482. inputs = db.Column(db.JSON)
  483. query = db.Column(db.Text, nullable=False)
  484. message = db.Column(db.JSON, nullable=False)
  485. message_tokens = db.Column(db.Integer, nullable=False, server_default=db.text('0'))
  486. message_unit_price = db.Column(db.Numeric(10, 4), nullable=False)
  487. message_price_unit = db.Column(db.Numeric(10, 7), nullable=False, server_default=db.text('0.001'))
  488. answer = db.Column(db.Text, nullable=False)
  489. answer_tokens = db.Column(db.Integer, nullable=False, server_default=db.text('0'))
  490. answer_unit_price = db.Column(db.Numeric(10, 4), nullable=False)
  491. answer_price_unit = db.Column(db.Numeric(10, 7), nullable=False, server_default=db.text('0.001'))
  492. provider_response_latency = db.Column(db.Float, nullable=False, server_default=db.text('0'))
  493. total_price = db.Column(db.Numeric(10, 7))
  494. currency = db.Column(db.String(255), nullable=False)
  495. from_source = db.Column(db.String(255), nullable=False)
  496. from_end_user_id = db.Column(UUID)
  497. from_account_id = db.Column(UUID)
  498. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  499. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  500. agent_based = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  501. @property
  502. def user_feedback(self):
  503. feedback = db.session.query(MessageFeedback).filter(MessageFeedback.message_id == self.id,
  504. MessageFeedback.from_source == 'user').first()
  505. return feedback
  506. @property
  507. def admin_feedback(self):
  508. feedback = db.session.query(MessageFeedback).filter(MessageFeedback.message_id == self.id,
  509. MessageFeedback.from_source == 'admin').first()
  510. return feedback
  511. @property
  512. def feedbacks(self):
  513. feedbacks = db.session.query(MessageFeedback).filter(MessageFeedback.message_id == self.id).all()
  514. return feedbacks
  515. @property
  516. def annotation(self):
  517. annotation = db.session.query(MessageAnnotation).filter(MessageAnnotation.message_id == self.id).first()
  518. return annotation
  519. @property
  520. def annotation_hit_history(self):
  521. annotation_history = (db.session.query(AppAnnotationHitHistory)
  522. .filter(AppAnnotationHitHistory.message_id == self.id).first())
  523. if annotation_history:
  524. annotation = (db.session.query(MessageAnnotation).
  525. filter(MessageAnnotation.id == annotation_history.annotation_id).first())
  526. return annotation
  527. return None
  528. @property
  529. def app_model_config(self):
  530. conversation = db.session.query(Conversation).filter(Conversation.id == self.conversation_id).first()
  531. if conversation:
  532. return db.session.query(AppModelConfig).filter(
  533. AppModelConfig.id == conversation.app_model_config_id).first()
  534. return None
  535. @property
  536. def in_debug_mode(self):
  537. return self.override_model_configs is not None
  538. @property
  539. def agent_thoughts(self):
  540. return db.session.query(MessageAgentThought).filter(MessageAgentThought.message_id == self.id) \
  541. .order_by(MessageAgentThought.position.asc()).all()
  542. @property
  543. def retriever_resources(self):
  544. return db.session.query(DatasetRetrieverResource).filter(DatasetRetrieverResource.message_id == self.id) \
  545. .order_by(DatasetRetrieverResource.position.asc()).all()
  546. @property
  547. def message_files(self):
  548. return db.session.query(MessageFile).filter(MessageFile.message_id == self.id).all()
  549. @property
  550. def files(self):
  551. message_files = self.message_files
  552. files = []
  553. for message_file in message_files:
  554. url = message_file.url
  555. if message_file.type == 'image':
  556. if message_file.transfer_method == 'local_file':
  557. upload_file = (db.session.query(UploadFile)
  558. .filter(
  559. UploadFile.id == message_file.upload_file_id
  560. ).first())
  561. url = UploadFileParser.get_image_data(
  562. upload_file=upload_file,
  563. force_url=True
  564. )
  565. if message_file.transfer_method == 'tool_file':
  566. # get extension
  567. if '.' in message_file.url:
  568. extension = f'.{message_file.url.split(".")[-1]}'
  569. if len(extension) > 10:
  570. extension = '.bin'
  571. else:
  572. extension = '.bin'
  573. # add sign url
  574. url = ToolFileParser.get_tool_file_manager().sign_file(file_id=message_file.id, extension=extension)
  575. files.append({
  576. 'id': message_file.id,
  577. 'type': message_file.type,
  578. 'url': url,
  579. 'belongs_to': message_file.belongs_to if message_file.belongs_to else 'user'
  580. })
  581. return files
  582. class MessageFeedback(db.Model):
  583. __tablename__ = 'message_feedbacks'
  584. __table_args__ = (
  585. db.PrimaryKeyConstraint('id', name='message_feedback_pkey'),
  586. db.Index('message_feedback_app_idx', 'app_id'),
  587. db.Index('message_feedback_message_idx', 'message_id', 'from_source'),
  588. db.Index('message_feedback_conversation_idx', 'conversation_id', 'from_source', 'rating')
  589. )
  590. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  591. app_id = db.Column(UUID, nullable=False)
  592. conversation_id = db.Column(UUID, nullable=False)
  593. message_id = db.Column(UUID, nullable=False)
  594. rating = db.Column(db.String(255), nullable=False)
  595. content = db.Column(db.Text)
  596. from_source = db.Column(db.String(255), nullable=False)
  597. from_end_user_id = db.Column(UUID)
  598. from_account_id = db.Column(UUID)
  599. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  600. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  601. @property
  602. def from_account(self):
  603. account = db.session.query(Account).filter(Account.id == self.from_account_id).first()
  604. return account
  605. class MessageFile(db.Model):
  606. __tablename__ = 'message_files'
  607. __table_args__ = (
  608. db.PrimaryKeyConstraint('id', name='message_file_pkey'),
  609. db.Index('message_file_message_idx', 'message_id'),
  610. db.Index('message_file_created_by_idx', 'created_by')
  611. )
  612. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  613. message_id = db.Column(UUID, nullable=False)
  614. type = db.Column(db.String(255), nullable=False)
  615. transfer_method = db.Column(db.String(255), nullable=False)
  616. url = db.Column(db.Text, nullable=True)
  617. belongs_to = db.Column(db.String(255), nullable=True)
  618. upload_file_id = db.Column(UUID, nullable=True)
  619. created_by_role = db.Column(db.String(255), nullable=False)
  620. created_by = db.Column(UUID, nullable=False)
  621. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  622. class MessageAnnotation(db.Model):
  623. __tablename__ = 'message_annotations'
  624. __table_args__ = (
  625. db.PrimaryKeyConstraint('id', name='message_annotation_pkey'),
  626. db.Index('message_annotation_app_idx', 'app_id'),
  627. db.Index('message_annotation_conversation_idx', 'conversation_id'),
  628. db.Index('message_annotation_message_idx', 'message_id')
  629. )
  630. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  631. app_id = db.Column(UUID, nullable=False)
  632. conversation_id = db.Column(UUID, db.ForeignKey('conversations.id'), nullable=True)
  633. message_id = db.Column(UUID, nullable=True)
  634. question = db.Column(db.Text, nullable=True)
  635. content = db.Column(db.Text, nullable=False)
  636. hit_count = db.Column(db.Integer, nullable=False, server_default=db.text('0'))
  637. account_id = db.Column(UUID, nullable=False)
  638. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  639. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  640. @property
  641. def account(self):
  642. account = db.session.query(Account).filter(Account.id == self.account_id).first()
  643. return account
  644. @property
  645. def annotation_create_account(self):
  646. account = db.session.query(Account).filter(Account.id == self.account_id).first()
  647. return account
  648. class AppAnnotationHitHistory(db.Model):
  649. __tablename__ = 'app_annotation_hit_histories'
  650. __table_args__ = (
  651. db.PrimaryKeyConstraint('id', name='app_annotation_hit_histories_pkey'),
  652. db.Index('app_annotation_hit_histories_app_idx', 'app_id'),
  653. db.Index('app_annotation_hit_histories_account_idx', 'account_id'),
  654. db.Index('app_annotation_hit_histories_annotation_idx', 'annotation_id'),
  655. db.Index('app_annotation_hit_histories_message_idx', 'message_id'),
  656. )
  657. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  658. app_id = db.Column(UUID, nullable=False)
  659. annotation_id = db.Column(UUID, nullable=False)
  660. source = db.Column(db.Text, nullable=False)
  661. question = db.Column(db.Text, nullable=False)
  662. account_id = db.Column(UUID, nullable=False)
  663. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  664. score = db.Column(Float, nullable=False, server_default=db.text('0'))
  665. message_id = db.Column(UUID, nullable=False)
  666. annotation_question = db.Column(db.Text, nullable=False)
  667. annotation_content = db.Column(db.Text, nullable=False)
  668. @property
  669. def account(self):
  670. account = (db.session.query(Account)
  671. .join(MessageAnnotation, MessageAnnotation.account_id == Account.id)
  672. .filter(MessageAnnotation.id == self.annotation_id).first())
  673. return account
  674. @property
  675. def annotation_create_account(self):
  676. account = db.session.query(Account).filter(Account.id == self.account_id).first()
  677. return account
  678. class AppAnnotationSetting(db.Model):
  679. __tablename__ = 'app_annotation_settings'
  680. __table_args__ = (
  681. db.PrimaryKeyConstraint('id', name='app_annotation_settings_pkey'),
  682. db.Index('app_annotation_settings_app_idx', 'app_id')
  683. )
  684. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  685. app_id = db.Column(UUID, nullable=False)
  686. score_threshold = db.Column(Float, nullable=False, server_default=db.text('0'))
  687. collection_binding_id = db.Column(UUID, nullable=False)
  688. created_user_id = db.Column(UUID, nullable=False)
  689. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  690. updated_user_id = db.Column(UUID, nullable=False)
  691. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  692. @property
  693. def created_account(self):
  694. account = (db.session.query(Account)
  695. .join(AppAnnotationSetting, AppAnnotationSetting.created_user_id == Account.id)
  696. .filter(AppAnnotationSetting.id == self.annotation_id).first())
  697. return account
  698. @property
  699. def updated_account(self):
  700. account = (db.session.query(Account)
  701. .join(AppAnnotationSetting, AppAnnotationSetting.updated_user_id == Account.id)
  702. .filter(AppAnnotationSetting.id == self.annotation_id).first())
  703. return account
  704. @property
  705. def collection_binding_detail(self):
  706. from .dataset import DatasetCollectionBinding
  707. collection_binding_detail = (db.session.query(DatasetCollectionBinding)
  708. .filter(DatasetCollectionBinding.id == self.collection_binding_id).first())
  709. return collection_binding_detail
  710. class OperationLog(db.Model):
  711. __tablename__ = 'operation_logs'
  712. __table_args__ = (
  713. db.PrimaryKeyConstraint('id', name='operation_log_pkey'),
  714. db.Index('operation_log_account_action_idx', 'tenant_id', 'account_id', 'action')
  715. )
  716. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  717. tenant_id = db.Column(UUID, nullable=False)
  718. account_id = db.Column(UUID, nullable=False)
  719. action = db.Column(db.String(255), nullable=False)
  720. content = db.Column(db.JSON)
  721. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  722. created_ip = db.Column(db.String(255), nullable=False)
  723. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  724. class EndUser(UserMixin, db.Model):
  725. __tablename__ = 'end_users'
  726. __table_args__ = (
  727. db.PrimaryKeyConstraint('id', name='end_user_pkey'),
  728. db.Index('end_user_session_id_idx', 'session_id', 'type'),
  729. db.Index('end_user_tenant_session_id_idx', 'tenant_id', 'session_id', 'type'),
  730. )
  731. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  732. tenant_id = db.Column(UUID, nullable=False)
  733. app_id = db.Column(UUID, nullable=True)
  734. type = db.Column(db.String(255), nullable=False)
  735. external_user_id = db.Column(db.String(255), nullable=True)
  736. name = db.Column(db.String(255))
  737. is_anonymous = db.Column(db.Boolean, nullable=False, server_default=db.text('true'))
  738. session_id = db.Column(db.String(255), nullable=False)
  739. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  740. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  741. class Site(db.Model):
  742. __tablename__ = 'sites'
  743. __table_args__ = (
  744. db.PrimaryKeyConstraint('id', name='site_pkey'),
  745. db.Index('site_app_id_idx', 'app_id'),
  746. db.Index('site_code_idx', 'code', 'status')
  747. )
  748. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  749. app_id = db.Column(UUID, nullable=False)
  750. title = db.Column(db.String(255), nullable=False)
  751. icon = db.Column(db.String(255))
  752. icon_background = db.Column(db.String(255))
  753. description = db.Column(db.Text)
  754. default_language = db.Column(db.String(255), nullable=False)
  755. copyright = db.Column(db.String(255))
  756. privacy_policy = db.Column(db.String(255))
  757. customize_domain = db.Column(db.String(255))
  758. customize_token_strategy = db.Column(db.String(255), nullable=False)
  759. prompt_public = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  760. status = db.Column(db.String(255), nullable=False, server_default=db.text("'normal'::character varying"))
  761. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  762. updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  763. code = db.Column(db.String(255))
  764. @staticmethod
  765. def generate_code(n):
  766. while True:
  767. result = generate_string(n)
  768. while db.session.query(Site).filter(Site.code == result).count() > 0:
  769. result = generate_string(n)
  770. return result
  771. @property
  772. def app_base_url(self):
  773. return (
  774. current_app.config['APP_WEB_URL'] if current_app.config['APP_WEB_URL'] else request.host_url.rstrip('/'))
  775. class ApiToken(db.Model):
  776. __tablename__ = 'api_tokens'
  777. __table_args__ = (
  778. db.PrimaryKeyConstraint('id', name='api_token_pkey'),
  779. db.Index('api_token_app_id_type_idx', 'app_id', 'type'),
  780. db.Index('api_token_token_idx', 'token', 'type'),
  781. db.Index('api_token_tenant_idx', 'tenant_id', 'type')
  782. )
  783. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  784. app_id = db.Column(UUID, nullable=True)
  785. tenant_id = db.Column(UUID, nullable=True)
  786. type = db.Column(db.String(16), nullable=False)
  787. token = db.Column(db.String(255), nullable=False)
  788. last_used_at = db.Column(db.DateTime, nullable=True)
  789. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  790. @staticmethod
  791. def generate_api_key(prefix, n):
  792. while True:
  793. result = prefix + generate_string(n)
  794. while db.session.query(ApiToken).filter(ApiToken.token == result).count() > 0:
  795. result = prefix + generate_string(n)
  796. return result
  797. class UploadFile(db.Model):
  798. __tablename__ = 'upload_files'
  799. __table_args__ = (
  800. db.PrimaryKeyConstraint('id', name='upload_file_pkey'),
  801. db.Index('upload_file_tenant_idx', 'tenant_id')
  802. )
  803. id = db.Column(UUID, server_default=db.text('uuid_generate_v4()'))
  804. tenant_id = db.Column(UUID, nullable=False)
  805. storage_type = db.Column(db.String(255), nullable=False)
  806. key = db.Column(db.String(255), nullable=False)
  807. name = db.Column(db.String(255), nullable=False)
  808. size = db.Column(db.Integer, nullable=False)
  809. extension = db.Column(db.String(255), nullable=False)
  810. mime_type = db.Column(db.String(255), nullable=True)
  811. created_by_role = db.Column(db.String(255), nullable=False, server_default=db.text("'account'::character varying"))
  812. created_by = db.Column(UUID, nullable=False)
  813. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  814. used = db.Column(db.Boolean, nullable=False, server_default=db.text('false'))
  815. used_by = db.Column(UUID, nullable=True)
  816. used_at = db.Column(db.DateTime, nullable=True)
  817. hash = db.Column(db.String(255), nullable=True)
  818. class ApiRequest(db.Model):
  819. __tablename__ = 'api_requests'
  820. __table_args__ = (
  821. db.PrimaryKeyConstraint('id', name='api_request_pkey'),
  822. db.Index('api_request_token_idx', 'tenant_id', 'api_token_id')
  823. )
  824. id = db.Column(UUID, nullable=False, server_default=db.text('uuid_generate_v4()'))
  825. tenant_id = db.Column(UUID, nullable=False)
  826. api_token_id = db.Column(UUID, nullable=False)
  827. path = db.Column(db.String(255), nullable=False)
  828. request = db.Column(db.Text, nullable=True)
  829. response = db.Column(db.Text, nullable=True)
  830. ip = db.Column(db.String(255), nullable=False)
  831. created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
  832. class MessageChain(db.Model):
  833. __tablename__ = 'message_chains'
  834. __table_args__ = (
  835. db.PrimaryKeyConstraint('id', name='message_chain_pkey'),
  836. db.Index('message_chain_message_id_idx', 'message_id')
  837. )
  838. id = db.Column(UUID, nullable=False, server_default=db.text('uuid_generate_v4()'))
  839. message_id = db.Column(UUID, nullable=False)
  840. type = db.Column(db.String(255), nullable=False)
  841. input = db.Column(db.Text, nullable=True)
  842. output = db.Column(db.Text, nullable=True)
  843. created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.current_timestamp())
  844. class MessageAgentThought(db.Model):
  845. __tablename__ = 'message_agent_thoughts'
  846. __table_args__ = (
  847. db.PrimaryKeyConstraint('id', name='message_agent_thought_pkey'),
  848. db.Index('message_agent_thought_message_id_idx', 'message_id'),
  849. db.Index('message_agent_thought_message_chain_id_idx', 'message_chain_id'),
  850. )
  851. id = db.Column(UUID, nullable=False, server_default=db.text('uuid_generate_v4()'))
  852. message_id = db.Column(UUID, nullable=False)
  853. message_chain_id = db.Column(UUID, nullable=True)
  854. position = db.Column(db.Integer, nullable=False)
  855. thought = db.Column(db.Text, nullable=True)
  856. tool = db.Column(db.Text, nullable=True)
  857. tool_labels_str = db.Column(db.Text, nullable=False, server_default=db.text("'{}'::text"))
  858. tool_input = db.Column(db.Text, nullable=True)
  859. observation = db.Column(db.Text, nullable=True)
  860. # plugin_id = db.Column(UUID, nullable=True) ## for future design
  861. tool_process_data = db.Column(db.Text, nullable=True)
  862. message = db.Column(db.Text, nullable=True)
  863. message_token = db.Column(db.Integer, nullable=True)
  864. message_unit_price = db.Column(db.Numeric, nullable=True)
  865. message_price_unit = db.Column(db.Numeric(10, 7), nullable=False, server_default=db.text('0.001'))
  866. message_files = db.Column(db.Text, nullable=True)
  867. answer = db.Column(db.Text, nullable=True)
  868. answer_token = db.Column(db.Integer, nullable=True)
  869. answer_unit_price = db.Column(db.Numeric, nullable=True)
  870. answer_price_unit = db.Column(db.Numeric(10, 7), nullable=False, server_default=db.text('0.001'))
  871. tokens = db.Column(db.Integer, nullable=True)
  872. total_price = db.Column(db.Numeric, nullable=True)
  873. currency = db.Column(db.String, nullable=True)
  874. latency = db.Column(db.Float, nullable=True)
  875. created_by_role = db.Column(db.String, nullable=False)
  876. created_by = db.Column(UUID, nullable=False)
  877. created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.current_timestamp())
  878. @property
  879. def files(self) -> list:
  880. if self.message_files:
  881. return json.loads(self.message_files)
  882. else:
  883. return []
  884. @property
  885. def tool_labels(self) -> dict:
  886. try:
  887. if self.tool_labels_str:
  888. return json.loads(self.tool_labels_str)
  889. else:
  890. return {}
  891. except Exception as e:
  892. return {}
  893. class DatasetRetrieverResource(db.Model):
  894. __tablename__ = 'dataset_retriever_resources'
  895. __table_args__ = (
  896. db.PrimaryKeyConstraint('id', name='dataset_retriever_resource_pkey'),
  897. db.Index('dataset_retriever_resource_message_id_idx', 'message_id'),
  898. )
  899. id = db.Column(UUID, nullable=False, server_default=db.text('uuid_generate_v4()'))
  900. message_id = db.Column(UUID, nullable=False)
  901. position = db.Column(db.Integer, nullable=False)
  902. dataset_id = db.Column(UUID, nullable=False)
  903. dataset_name = db.Column(db.Text, nullable=False)
  904. document_id = db.Column(UUID, nullable=False)
  905. document_name = db.Column(db.Text, nullable=False)
  906. data_source_type = db.Column(db.Text, nullable=False)
  907. segment_id = db.Column(UUID, nullable=False)
  908. score = db.Column(db.Float, nullable=True)
  909. content = db.Column(db.Text, nullable=False)
  910. hit_count = db.Column(db.Integer, nullable=True)
  911. word_count = db.Column(db.Integer, nullable=True)
  912. segment_position = db.Column(db.Integer, nullable=True)
  913. index_node_hash = db.Column(db.Text, nullable=True)
  914. retriever_from = db.Column(db.Text, nullable=False)
  915. created_by = db.Column(UUID, nullable=False)
  916. created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.current_timestamp())