mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
feat: Advanced Application support to use SQL Examples
This commit is contained in:
@@ -505,8 +505,12 @@ class LLMService:
|
||||
|
||||
self.chat_question.terminologies = get_terminology_template(_session, self.chat_question.question, oid,
|
||||
ds_id)
|
||||
self.chat_question.data_training = get_training_template(_session, self.chat_question.question, ds_id,
|
||||
oid)
|
||||
if self.current_assistant and self.current_assistant.type == 1:
|
||||
self.chat_question.data_training = get_training_template(_session, self.chat_question.question,
|
||||
oid, None, self.current_assistant.id)
|
||||
else:
|
||||
self.chat_question.data_training = get_training_template(_session, self.chat_question.question,
|
||||
oid, ds_id)
|
||||
if SQLBotLicenseUtil.valid():
|
||||
self.chat_question.custom_prompt = find_custom_prompts(_session, CustomPromptTypeEnum.GENERATE_SQL,
|
||||
oid, ds_id)
|
||||
@@ -902,8 +906,12 @@ class LLMService:
|
||||
ds_id = self.ds.id if isinstance(self.ds, CoreDatasource) else None
|
||||
self.chat_question.terminologies = get_terminology_template(_session, self.chat_question.question,
|
||||
oid, ds_id)
|
||||
self.chat_question.data_training = get_training_template(_session, self.chat_question.question,
|
||||
ds_id, oid)
|
||||
if self.current_assistant and self.current_assistant.type == 1:
|
||||
self.chat_question.data_training = get_training_template(_session, self.chat_question.question,
|
||||
oid, None, self.current_assistant.id)
|
||||
else:
|
||||
self.chat_question.data_training = get_training_template(_session, self.chat_question.question,
|
||||
oid, ds_id)
|
||||
if SQLBotLicenseUtil.valid():
|
||||
self.chat_question.custom_prompt = find_custom_prompts(_session,
|
||||
CustomPromptTypeEnum.GENERATE_SQL,
|
||||
|
||||
@@ -9,8 +9,9 @@ from sqlalchemy import and_, select, func, delete, update, or_
|
||||
from sqlalchemy import text
|
||||
|
||||
from apps.ai_model.embedding import EmbeddingModelCache
|
||||
from apps.data_training.models.data_training_model import DataTrainingInfo, DataTraining
|
||||
from apps.data_training.models.data_training_model import DataTrainingInfo, DataTraining, DataTrainingInfoResult
|
||||
from apps.datasource.models.datasource import CoreDatasource
|
||||
from apps.system.models.system_model import AssistantModel
|
||||
from apps.template.generate_chart.generator import get_base_data_training_template
|
||||
from common.core.config import settings
|
||||
from common.core.deps import SessionDep, Trans
|
||||
@@ -19,7 +20,7 @@ from common.utils.embedding_threads import run_save_data_training_embeddings
|
||||
|
||||
def page_data_training(session: SessionDep, current_page: int = 1, page_size: int = 10, name: Optional[str] = None,
|
||||
oid: Optional[int] = 1):
|
||||
_list: List[DataTrainingInfo] = []
|
||||
_list: List[DataTrainingInfoResult] = []
|
||||
|
||||
current_page = max(1, current_page)
|
||||
page_size = max(10, page_size)
|
||||
@@ -63,8 +64,12 @@ def page_data_training(session: SessionDep, current_page: int = 1, page_size: in
|
||||
DataTraining.create_time,
|
||||
DataTraining.description,
|
||||
DataTraining.enabled,
|
||||
DataTraining.advanced_application,
|
||||
AssistantModel.name.label('advanced_application_name'),
|
||||
)
|
||||
.outerjoin(CoreDatasource, and_(DataTraining.datasource == CoreDatasource.id))
|
||||
.outerjoin(AssistantModel,
|
||||
and_(DataTraining.advanced_application == AssistantModel.id, AssistantModel.type == 1))
|
||||
.where(and_(DataTraining.id.in_(paginated_parent_ids)))
|
||||
.order_by(DataTraining.create_time.desc())
|
||||
)
|
||||
@@ -72,15 +77,17 @@ def page_data_training(session: SessionDep, current_page: int = 1, page_size: in
|
||||
result = session.execute(stmt)
|
||||
|
||||
for row in result:
|
||||
_list.append(DataTrainingInfo(
|
||||
id=row.id,
|
||||
oid=row.oid,
|
||||
_list.append(DataTrainingInfoResult(
|
||||
id=str(row.id),
|
||||
oid=str(row.oid),
|
||||
datasource=row.datasource,
|
||||
datasource_name=row.name,
|
||||
question=row.question,
|
||||
create_time=row.create_time,
|
||||
description=row.description,
|
||||
enabled=row.enabled,
|
||||
advanced_application=str(row.advanced_application) if row.advanced_application else None,
|
||||
advanced_application_name=row.advanced_application_name,
|
||||
))
|
||||
|
||||
return current_page, page_size, total_count, total_pages, _list
|
||||
@@ -88,15 +95,29 @@ def page_data_training(session: SessionDep, current_page: int = 1, page_size: in
|
||||
|
||||
def create_training(session: SessionDep, info: DataTrainingInfo, oid: int, trans: Trans):
|
||||
create_time = datetime.datetime.now()
|
||||
if info.datasource is None:
|
||||
raise Exception(trans("i18n_data_training.datasource_cannot_be_none"))
|
||||
if info.datasource is None and info.advanced_application is None:
|
||||
if oid == 1:
|
||||
raise Exception(trans("i18n_data_training.datasource_assistant_cannot_be_none"))
|
||||
else:
|
||||
raise Exception(trans("i18n_data_training.datasource_cannot_be_none"))
|
||||
|
||||
parent = DataTraining(question=info.question, create_time=create_time, description=info.description, oid=oid,
|
||||
datasource=info.datasource, enabled=info.enabled)
|
||||
datasource=info.datasource, enabled=info.enabled,
|
||||
advanced_application=info.advanced_application)
|
||||
|
||||
stmt = select(DataTraining.id).where(and_(DataTraining.question == info.question, DataTraining.oid == oid))
|
||||
|
||||
if info.datasource is not None and info.advanced_application is not None:
|
||||
stmt = stmt.where(
|
||||
or_(DataTraining.datasource == info.datasource,
|
||||
DataTraining.advanced_application == info.advanced_application))
|
||||
elif info.datasource is not None and info.advanced_application is None:
|
||||
stmt = stmt.where(and_(DataTraining.datasource == info.datasource))
|
||||
elif info.datasource is None and info.advanced_application is not None:
|
||||
stmt = stmt.where(and_(DataTraining.advanced_application == info.advanced_application))
|
||||
|
||||
exists = session.query(stmt.exists()).scalar()
|
||||
|
||||
exists = session.query(
|
||||
session.query(DataTraining).filter(
|
||||
and_(DataTraining.question == info.question, DataTraining.oid == oid,
|
||||
DataTraining.datasource == info.datasource)).exists()).scalar()
|
||||
if exists:
|
||||
raise Exception(trans("i18n_data_training.exists_in_db"))
|
||||
|
||||
@@ -116,8 +137,11 @@ def create_training(session: SessionDep, info: DataTrainingInfo, oid: int, trans
|
||||
|
||||
|
||||
def update_training(session: SessionDep, info: DataTrainingInfo, oid: int, trans: Trans):
|
||||
if info.datasource is None:
|
||||
raise Exception(trans("i18n_data_training.datasource_cannot_be_none"))
|
||||
if info.datasource is None and info.advanced_application is None:
|
||||
if oid == 1:
|
||||
raise Exception(trans("i18n_data_training.datasource_assistant_cannot_be_none"))
|
||||
else:
|
||||
raise Exception(trans("i18n_data_training.datasource_cannot_be_none"))
|
||||
|
||||
count = session.query(DataTraining).filter(
|
||||
DataTraining.id == info.id
|
||||
@@ -125,11 +149,20 @@ def update_training(session: SessionDep, info: DataTrainingInfo, oid: int, trans
|
||||
if count == 0:
|
||||
raise Exception(trans('i18n_data_training.data_training_not_exists'))
|
||||
|
||||
exists = session.query(
|
||||
session.query(DataTraining).filter(
|
||||
and_(DataTraining.question == info.question, DataTraining.oid == oid,
|
||||
DataTraining.datasource == info.datasource,
|
||||
DataTraining.id != info.id)).exists()).scalar()
|
||||
stmt = select(DataTraining.id).where(
|
||||
and_(DataTraining.question == info.question, DataTraining.oid == oid, DataTraining.id != info.id))
|
||||
|
||||
if info.datasource is not None and info.advanced_application is not None:
|
||||
stmt = stmt.where(
|
||||
or_(DataTraining.datasource == info.datasource,
|
||||
DataTraining.advanced_application == info.advanced_application))
|
||||
elif info.datasource is not None and info.advanced_application is None:
|
||||
stmt = stmt.where(and_(DataTraining.datasource == info.datasource))
|
||||
elif info.datasource is None and info.advanced_application is not None:
|
||||
stmt = stmt.where(and_(DataTraining.advanced_application == info.advanced_application))
|
||||
|
||||
exists = session.query(stmt.exists()).scalar()
|
||||
|
||||
if exists:
|
||||
raise Exception(trans("i18n_data_training.exists_in_db"))
|
||||
|
||||
@@ -138,6 +171,7 @@ def update_training(session: SessionDep, info: DataTrainingInfo, oid: int, trans
|
||||
description=info.description,
|
||||
datasource=info.datasource,
|
||||
enabled=info.enabled,
|
||||
advanced_application=info.advanced_application,
|
||||
)
|
||||
session.execute(stmt)
|
||||
session.commit()
|
||||
@@ -231,9 +265,21 @@ WHERE similarity > {settings.EMBEDDING_DATA_TRAINING_SIMILARITY} and oid = :oid
|
||||
ORDER BY similarity DESC
|
||||
LIMIT {settings.EMBEDDING_DATA_TRAINING_TOP_COUNT}
|
||||
"""
|
||||
embedding_sql_in_advanced_application = f"""
|
||||
SELECT id, datasource, question, similarity
|
||||
FROM
|
||||
(SELECT id, datasource, question, oid, enabled,
|
||||
( 1 - (embedding <=> :embedding_array) ) AS similarity
|
||||
FROM data_training AS child
|
||||
) TEMP
|
||||
WHERE similarity > {settings.EMBEDDING_DATA_TRAINING_SIMILARITY} and oid = :oid and advanced_application = :advanced_application and enabled = true
|
||||
ORDER BY similarity DESC
|
||||
LIMIT {settings.EMBEDDING_DATA_TRAINING_TOP_COUNT}
|
||||
"""
|
||||
|
||||
|
||||
def select_training_by_question(session: SessionDep, question: str, oid: int, datasource: int):
|
||||
def select_training_by_question(session: SessionDep, question: str, oid: int, datasource: Optional[int] = None,
|
||||
advanced_application_id: Optional[int] = None):
|
||||
if question.strip() == "":
|
||||
return []
|
||||
|
||||
@@ -248,10 +294,13 @@ def select_training_by_question(session: SessionDep, question: str, oid: int, da
|
||||
.where(
|
||||
and_(or_(text(":sentence ILIKE '%' || question || '%'"), text("question ILIKE '%' || :sentence || '%'")),
|
||||
DataTraining.oid == oid,
|
||||
DataTraining.datasource == datasource,
|
||||
DataTraining.enabled == True,)
|
||||
DataTraining.enabled == True)
|
||||
)
|
||||
)
|
||||
if advanced_application_id is not None:
|
||||
stmt = stmt.where(and_(DataTraining.advanced_application == advanced_application_id))
|
||||
else:
|
||||
stmt = stmt.where(and_(DataTraining.datasource == datasource))
|
||||
|
||||
results = session.execute(stmt, {'sentence': question}).fetchall()
|
||||
|
||||
@@ -264,8 +313,13 @@ def select_training_by_question(session: SessionDep, question: str, oid: int, da
|
||||
|
||||
embedding = model.embed_query(question)
|
||||
|
||||
results = session.execute(text(embedding_sql),
|
||||
{'embedding_array': str(embedding), 'oid': oid, 'datasource': datasource})
|
||||
if advanced_application_id is not None:
|
||||
results = session.execute(text(embedding_sql_in_advanced_application),
|
||||
{'embedding_array': str(embedding), 'oid': oid,
|
||||
'advanced_application': advanced_application_id})
|
||||
else:
|
||||
results = session.execute(text(embedding_sql),
|
||||
{'embedding_array': str(embedding), 'oid': oid, 'datasource': datasource})
|
||||
|
||||
for row in results:
|
||||
_list.append(DataTraining(id=row.id, question=row.question))
|
||||
@@ -328,12 +382,13 @@ def to_xml_string(_dict: list[dict] | dict, root: str = 'sql-examples') -> str:
|
||||
return pretty_xml
|
||||
|
||||
|
||||
def get_training_template(session: SessionDep, question: str, datasource: int, oid: Optional[int] = 1) -> str:
|
||||
def get_training_template(session: SessionDep, question: str, oid: Optional[int] = 1, datasource: Optional[int] = None,
|
||||
advanced_application_id: Optional[int] = None) -> str:
|
||||
if not oid:
|
||||
oid = 1
|
||||
if not datasource:
|
||||
if not datasource and not advanced_application_id:
|
||||
return ''
|
||||
_results = select_training_by_question(session, question, oid, datasource)
|
||||
_results = select_training_by_question(session, question, oid, datasource, advanced_application_id)
|
||||
if _results and len(_results) > 0:
|
||||
data_training = to_xml_string(_results)
|
||||
template = get_base_data_training_template().format(data_training=data_training)
|
||||
|
||||
@@ -17,6 +17,7 @@ class DataTraining(SQLModel, table=True):
|
||||
description: Optional[str] = Field(sa_column=Column(Text, nullable=True))
|
||||
embedding: Optional[List[float]] = Field(sa_column=Column(VECTOR(), nullable=True))
|
||||
enabled: Optional[bool] = Field(sa_column=Column(Boolean, default=True))
|
||||
advanced_application: Optional[int] = Field(sa_column=Column(BigInteger, nullable=True))
|
||||
|
||||
|
||||
class DataTrainingInfo(BaseModel):
|
||||
@@ -28,3 +29,18 @@ class DataTrainingInfo(BaseModel):
|
||||
question: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
enabled: Optional[bool] = True
|
||||
advanced_application: Optional[int] = None
|
||||
advanced_application_name: Optional[str] = None
|
||||
|
||||
|
||||
class DataTrainingInfoResult(BaseModel):
|
||||
id: Optional[str] = None
|
||||
oid: Optional[str] = None
|
||||
datasource: Optional[int] = None
|
||||
datasource_name: Optional[str] = None
|
||||
create_time: Optional[datetime] = None
|
||||
question: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
enabled: Optional[bool] = True
|
||||
advanced_application: Optional[str] = None
|
||||
advanced_application_name: Optional[str] = None
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
from datetime import timedelta
|
||||
import json
|
||||
import os
|
||||
from datetime import timedelta
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, Form, HTTPException, Query, Request, Response, UploadFile
|
||||
from fastapi.responses import StreamingResponse
|
||||
from sqlbot_xpack.file_utils import SQLBotFileUtils
|
||||
from sqlmodel import select
|
||||
|
||||
from apps.system.crud.assistant import get_assistant_info
|
||||
from apps.system.crud.assistant_manage import dynamic_upgrade_cors, save
|
||||
from apps.system.models.system_model import AssistantModel
|
||||
from apps.system.schemas.auth import CacheName, CacheNamespace
|
||||
from apps.system.schemas.system_schema import AssistantBase, AssistantDTO, AssistantUiSchema, AssistantValidator
|
||||
from common.core.config import settings
|
||||
from common.core.deps import SessionDep, Trans
|
||||
from common.core.security import create_access_token
|
||||
from common.core.sqlbot_cache import clear_cache
|
||||
from common.utils.time import get_timestamp
|
||||
|
||||
from common.core.config import settings
|
||||
from common.utils.utils import get_origin_from_referer
|
||||
from sqlbot_xpack.file_utils import SQLBotFileUtils
|
||||
|
||||
router = APIRouter(tags=["system/assistant"], prefix="/system/assistant")
|
||||
|
||||
@router.get("/info/{id}")
|
||||
|
||||
@router.get("/info/{id}")
|
||||
async def info(request: Request, response: Response, session: SessionDep, trans: Trans, id: int) -> AssistantModel:
|
||||
if not id:
|
||||
raise Exception('miss assistant id')
|
||||
@@ -32,13 +33,14 @@ async def info(request: Request, response: Response, session: SessionDep, trans:
|
||||
response.headers["Access-Control-Allow-Origin"] = db_model.domain
|
||||
origin = request.headers.get("origin") or get_origin_from_referer(request)
|
||||
if not origin:
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin = origin or ''))
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=origin or ''))
|
||||
origin = origin.rstrip('/')
|
||||
if origin != db_model.domain:
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin = origin or ''))
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=origin or ''))
|
||||
return db_model
|
||||
|
||||
@router.get("/app/{appId}")
|
||||
|
||||
@router.get("/app/{appId}")
|
||||
async def getApp(request: Request, response: Response, session: SessionDep, trans: Trans, appId: str) -> AssistantModel:
|
||||
if not appId:
|
||||
raise Exception('miss assistant appId')
|
||||
@@ -49,27 +51,28 @@ async def getApp(request: Request, response: Response, session: SessionDep, tran
|
||||
response.headers["Access-Control-Allow-Origin"] = db_model.domain
|
||||
origin = request.headers.get("origin") or get_origin_from_referer(request)
|
||||
if not origin:
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin = origin or ''))
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=origin or ''))
|
||||
origin = origin.rstrip('/')
|
||||
if origin != db_model.domain:
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin = origin or ''))
|
||||
raise RuntimeError(trans('i18n_embedded.invalid_origin', origin=origin or ''))
|
||||
return db_model
|
||||
|
||||
@router.get("/validator", response_model=AssistantValidator)
|
||||
|
||||
@router.get("/validator", response_model=AssistantValidator)
|
||||
async def validator(session: SessionDep, id: int, virtual: Optional[int] = Query(None)):
|
||||
if not id:
|
||||
raise Exception('miss assistant id')
|
||||
|
||||
|
||||
db_model = await get_assistant_info(session=session, assistant_id=id)
|
||||
if not db_model:
|
||||
return AssistantValidator()
|
||||
db_model = AssistantModel.model_validate(db_model)
|
||||
assistant_oid = 1
|
||||
if(db_model.type == 0):
|
||||
if (db_model.type == 0):
|
||||
configuration = db_model.configuration
|
||||
config_obj = json.loads(configuration) if configuration else {}
|
||||
assistant_oid = config_obj.get('oid', 1)
|
||||
|
||||
|
||||
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
assistantDict = {
|
||||
"id": virtual, "account": 'sqlbot-inner-assistant', "oid": assistant_oid, "assistant_id": id
|
||||
@@ -78,24 +81,26 @@ async def validator(session: SessionDep, id: int, virtual: Optional[int] = Query
|
||||
assistantDict, expires_delta=access_token_expires
|
||||
)
|
||||
return AssistantValidator(True, True, True, access_token)
|
||||
|
||||
|
||||
|
||||
@router.get('/picture/{file_id}')
|
||||
async def picture(file_id: str):
|
||||
file_path = SQLBotFileUtils.get_file_path(file_id=file_id)
|
||||
if not os.path.exists(file_path):
|
||||
raise HTTPException(status_code=404, detail="File not found")
|
||||
|
||||
|
||||
if file_id.lower().endswith(".svg"):
|
||||
media_type = "image/svg+xml"
|
||||
else:
|
||||
media_type = "image/jpeg"
|
||||
|
||||
|
||||
def iterfile():
|
||||
with open(file_path, mode="rb") as f:
|
||||
yield from f
|
||||
|
||||
|
||||
return StreamingResponse(iterfile(), media_type=media_type)
|
||||
|
||||
|
||||
@router.patch('/ui')
|
||||
async def ui(session: SessionDep, data: str = Form(), files: List[UploadFile] = []):
|
||||
json_data = json.loads(data)
|
||||
@@ -106,7 +111,7 @@ async def ui(session: SessionDep, data: str = Form(), files: List[UploadFile] =
|
||||
raise ValueError(f"AssistantModel with id {id} not found")
|
||||
configuration = db_model.configuration
|
||||
config_obj = json.loads(configuration) if configuration else {}
|
||||
|
||||
|
||||
ui_schema_dict = uiSchema.model_dump(exclude_none=True, exclude_unset=True)
|
||||
if files:
|
||||
for file in files:
|
||||
@@ -114,45 +119,57 @@ async def ui(session: SessionDep, data: str = Form(), files: List[UploadFile] =
|
||||
file_name, flag_name = SQLBotFileUtils.split_filename_and_flag(origin_file_name)
|
||||
file.filename = file_name
|
||||
if flag_name == 'logo' or flag_name == 'float_icon':
|
||||
SQLBotFileUtils.check_file(file=file, file_types=[".jpg", ".jpeg", ".png", ".svg"], limit_file_size=(10 * 1024 * 1024))
|
||||
SQLBotFileUtils.check_file(file=file, file_types=[".jpg", ".jpeg", ".png", ".svg"],
|
||||
limit_file_size=(10 * 1024 * 1024))
|
||||
if config_obj.get(flag_name):
|
||||
SQLBotFileUtils.delete_file(config_obj.get(flag_name))
|
||||
file_id = await SQLBotFileUtils.upload(file)
|
||||
ui_schema_dict[flag_name] = file_id
|
||||
else:
|
||||
raise ValueError(f"Unsupported file flag: {flag_name}")
|
||||
|
||||
|
||||
for flag_name in ['logo', 'float_icon']:
|
||||
file_val = config_obj.get(flag_name)
|
||||
if file_val and not ui_schema_dict.get(flag_name):
|
||||
config_obj[flag_name] = None
|
||||
SQLBotFileUtils.delete_file(file_val)
|
||||
|
||||
|
||||
for attr, value in ui_schema_dict.items():
|
||||
if attr != 'id' and not attr.startswith("__"):
|
||||
config_obj[attr] = value
|
||||
|
||||
|
||||
db_model.configuration = json.dumps(config_obj, ensure_ascii=False)
|
||||
session.add(db_model)
|
||||
session.commit()
|
||||
await clear_ui_cache(db_model.id)
|
||||
|
||||
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="id")
|
||||
|
||||
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="id")
|
||||
async def clear_ui_cache(id: int):
|
||||
pass
|
||||
|
||||
|
||||
@router.get("", response_model=list[AssistantModel])
|
||||
async def query(session: SessionDep):
|
||||
list_result = session.exec(select(AssistantModel).where(AssistantModel.type != 4).order_by(AssistantModel.name, AssistantModel.create_time)).all()
|
||||
list_result = session.exec(select(AssistantModel).where(AssistantModel.type != 4).order_by(AssistantModel.name,
|
||||
AssistantModel.create_time)).all()
|
||||
return list_result
|
||||
|
||||
|
||||
@router.get("/advanced_application", response_model=list[AssistantModel])
|
||||
async def query_advanced_application(session: SessionDep):
|
||||
list_result = session.exec(select(AssistantModel).where(AssistantModel.type == 1).order_by(AssistantModel.name,
|
||||
AssistantModel.create_time)).all()
|
||||
return list_result
|
||||
|
||||
|
||||
@router.post("")
|
||||
async def add(request: Request, session: SessionDep, creator: AssistantBase):
|
||||
await save(request, session, creator)
|
||||
|
||||
|
||||
|
||||
@router.put("")
|
||||
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="editor.id")
|
||||
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="editor.id")
|
||||
async def update(request: Request, session: SessionDep, editor: AssistantDTO):
|
||||
id = editor.id
|
||||
db_model = session.get(AssistantModel, id)
|
||||
@@ -164,7 +181,8 @@ async def update(request: Request, session: SessionDep, editor: AssistantDTO):
|
||||
session.commit()
|
||||
dynamic_upgrade_cors(request=request, session=session)
|
||||
|
||||
@router.get("/{id}", response_model=AssistantModel)
|
||||
|
||||
@router.get("/{id}", response_model=AssistantModel)
|
||||
async def get_one(session: SessionDep, id: int):
|
||||
db_model = await get_assistant_info(session=session, assistant_id=id)
|
||||
if not db_model:
|
||||
@@ -172,8 +190,9 @@ async def get_one(session: SessionDep, id: int):
|
||||
db_model = AssistantModel.model_validate(db_model)
|
||||
return db_model
|
||||
|
||||
|
||||
@router.delete("/{id}")
|
||||
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="id")
|
||||
@clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="id")
|
||||
async def delete(request: Request, session: SessionDep, id: int):
|
||||
db_model = session.get(AssistantModel, id)
|
||||
if not db_model:
|
||||
@@ -181,10 +200,3 @@ async def delete(request: Request, session: SessionDep, id: int):
|
||||
session.delete(db_model)
|
||||
session.commit()
|
||||
dynamic_upgrade_cors(request=request, session=session)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -46,10 +46,11 @@
|
||||
},
|
||||
"i18n_data_training": {
|
||||
"datasource_cannot_be_none": "Datasource cannot be none or empty",
|
||||
"datasource_assistant_cannot_be_none": "Datasource or Advanced application cannot be all none",
|
||||
"data_training_not_exists": "Example does not exists",
|
||||
"exists_in_db": "Question exists"
|
||||
},
|
||||
"i18n_custom_prompt": {
|
||||
"i18n_custom_prompt": {
|
||||
"exists_in_db": "Prompt name exists",
|
||||
"not_exists": "Prompt does not exists"
|
||||
},
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
},
|
||||
"i18n_data_training": {
|
||||
"datasource_cannot_be_none": "데이터 소스를 선택해 주세요",
|
||||
"datasource_assistant_cannot_be_none": "데이터 소스와 고급 애플리케이션이 모두 비어 있을 수는 없습니다.",
|
||||
"data_training_not_exists": "예제가 존재하지 않습니다",
|
||||
"exists_in_db": "질문이 이미 존재합니다"
|
||||
},
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
},
|
||||
"i18n_data_training": {
|
||||
"datasource_cannot_be_none": "数据源不能为空",
|
||||
"datasource_assistant_cannot_be_none": "数据源或高级应用不能都为空",
|
||||
"data_training_not_exists": "该示例不存在",
|
||||
"exists_in_db": "该问题已存在"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
export const getList = () => request.get('/system/assistant')
|
||||
export const getAdvancedApplicationList = () =>
|
||||
request.get('/system/assistant/advanced_application')
|
||||
export const updateAssistant = (data: any) => request.put('/system/assistant', data)
|
||||
export const saveAssistant = (data: any) => request.post('/system/assistant', data)
|
||||
export const getOne = (id: any) => request.get(`/system/assistant/${id}`)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, reactive, ref, unref } from 'vue'
|
||||
import { computed, nextTick, onMounted, reactive, ref, unref } from 'vue'
|
||||
import icon_export_outlined from '@/assets/svg/icon_export_outlined.svg'
|
||||
import { trainingApi } from '@/api/training'
|
||||
import { formatTimestamp } from '@/utils/date'
|
||||
@@ -12,17 +12,21 @@ import IconOpeDelete from '@/assets/svg/icon_delete.svg'
|
||||
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { cloneDeep, forEach } from 'lodash-es'
|
||||
import { getAdvancedApplicationList } from '@/api/embedded.ts'
|
||||
|
||||
interface Form {
|
||||
id?: string | null
|
||||
question: string | null
|
||||
datasource: string | null
|
||||
datasource_name: string | null
|
||||
advanced_application: string | null
|
||||
advanced_application_name: string | null
|
||||
description: string | null
|
||||
}
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { t } = useI18n()
|
||||
const multipleSelectionAll = ref<any[]>([])
|
||||
const keywords = ref('')
|
||||
@@ -31,6 +35,7 @@ const searchLoading = ref(false)
|
||||
const { copy } = useClipboard({ legacy: true })
|
||||
|
||||
const options = ref<any[]>([])
|
||||
const adv_options = ref<any[]>([])
|
||||
const selectable = () => {
|
||||
return true
|
||||
}
|
||||
@@ -38,6 +43,10 @@ onMounted(() => {
|
||||
search()
|
||||
})
|
||||
|
||||
const isDefaultOrg = computed(() => {
|
||||
return userStore.oid === '1'
|
||||
})
|
||||
|
||||
const dialogFormVisible = ref<boolean>(false)
|
||||
const multipleTableRef = ref()
|
||||
const isIndeterminate = ref(true)
|
||||
@@ -57,6 +66,8 @@ const defaultForm = {
|
||||
description: null,
|
||||
datasource: null,
|
||||
datasource_name: null,
|
||||
advanced_application: null,
|
||||
advanced_application_name: null,
|
||||
}
|
||||
const pageForm = ref<Form>(cloneDeep(defaultForm))
|
||||
const copyCode = () => {
|
||||
@@ -217,31 +228,43 @@ const search = () => {
|
||||
|
||||
const termFormRef = ref()
|
||||
|
||||
const rules = {
|
||||
question: [
|
||||
{
|
||||
required: true,
|
||||
message: t('datasource.please_enter') + t('common.empty') + t('training.problem_description'),
|
||||
},
|
||||
],
|
||||
datasource: [
|
||||
{
|
||||
required: true,
|
||||
message: t('datasource.Please_select') + t('common.empty') + t('ds.title'),
|
||||
},
|
||||
],
|
||||
description: [
|
||||
{
|
||||
required: true,
|
||||
message: t('datasource.please_enter') + t('common.empty') + t('training.sample_sql'),
|
||||
},
|
||||
],
|
||||
}
|
||||
const rules = computed(() => {
|
||||
let _list = {
|
||||
question: [
|
||||
{
|
||||
required: true,
|
||||
message:
|
||||
t('datasource.please_enter') + t('common.empty') + t('training.problem_description'),
|
||||
},
|
||||
],
|
||||
datasource: [] as any,
|
||||
description: [
|
||||
{
|
||||
required: true,
|
||||
message: t('datasource.please_enter') + t('common.empty') + t('training.sample_sql'),
|
||||
},
|
||||
],
|
||||
}
|
||||
if (!isDefaultOrg.value) {
|
||||
_list.datasource = [
|
||||
{
|
||||
required: true,
|
||||
message: t('datasource.Please_select') + t('common.empty') + t('ds.title'),
|
||||
},
|
||||
]
|
||||
}
|
||||
return _list
|
||||
})
|
||||
|
||||
const list = () => {
|
||||
datasourceApi.list().then((res: any) => {
|
||||
options.value = res || []
|
||||
})
|
||||
if (isDefaultOrg.value) {
|
||||
getAdvancedApplicationList().then((res: any) => {
|
||||
adv_options.value = res || []
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const saveHandler = () => {
|
||||
@@ -387,11 +410,16 @@ const onRowFormClose = () => {
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="datasource_name" :label="$t('ds.title')" min-width="240">
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('ds.status')" width="180">
|
||||
<el-table-column prop="datasource_name" :label="$t('ds.title')" min-width="180" />
|
||||
<el-table-column
|
||||
v-if="isDefaultOrg"
|
||||
prop="advanced_application_name"
|
||||
:label="$t('embedded.advanced_application')"
|
||||
min-width="180"
|
||||
/>
|
||||
<el-table-column :label="t('ds.status')" width="100">
|
||||
<template #default="scope">
|
||||
<div @click.stop style="display: flex; align-items: center">
|
||||
<div style="display: flex; align-items: center" @click.stop>
|
||||
<el-switch
|
||||
v-model="scope.row.enabled"
|
||||
size="small"
|
||||
@@ -530,12 +558,38 @@ const onRowFormClose = () => {
|
||||
<el-select
|
||||
v-model="pageForm.datasource"
|
||||
filterable
|
||||
clearable
|
||||
:placeholder="$t('datasource.Please_select') + $t('common.empty') + $t('ds.title')"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
v-if="isDefaultOrg"
|
||||
prop="advanced_application"
|
||||
:label="t('embedded.advanced_application')"
|
||||
>
|
||||
<el-select
|
||||
v-model="pageForm.advanced_application"
|
||||
filterable
|
||||
clearable
|
||||
:placeholder="
|
||||
$t('datasource.Please_select') +
|
||||
$t('common.empty') +
|
||||
$t('embedded.advanced_application')
|
||||
"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in adv_options"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div v-loading="updateLoading" class="dialog-footer">
|
||||
@@ -577,6 +631,11 @@ const onRowFormClose = () => {
|
||||
{{ pageForm.datasource_name }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="isDefaultOrg" :label="t('embedded.advanced_application')">
|
||||
<div class="content">
|
||||
{{ pageForm.advanced_application_name }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user