mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
Merge branch 'main' of https://github.com/dataease/SQLBot
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
"""035_create_chat_log
|
||||
|
||||
Revision ID: 68a06302cf70
|
||||
Revises: 29559ee607af
|
||||
Create Date: 2025-08-18 16:02:43.353110
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel.sql.sqltypes
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '68a06302cf70'
|
||||
down_revision = '646e7ca28e0e'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
sql='''
|
||||
CREATE OR REPLACE FUNCTION safe_jsonb_cast(text) RETURNS jsonb AS
|
||||
$$
|
||||
BEGIN
|
||||
RETURN $1::jsonb;
|
||||
EXCEPTION
|
||||
WHEN others THEN
|
||||
RETURN to_json($1::text)::jsonb;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
INSERT INTO chat_log(type, operate, pid, ai_modal_id, messages, start_time, finish_time, token_usage, reasoning_content)
|
||||
SELECT '0',
|
||||
'0',
|
||||
id,
|
||||
ai_modal_id,
|
||||
safe_jsonb_cast(full_sql_message),
|
||||
create_time,
|
||||
finish_time,
|
||||
safe_jsonb_cast(token_sql),
|
||||
safe_jsonb_cast(sql_answer)->>'reasoning_content'
|
||||
FROM chat_record
|
||||
WHERE full_sql_message IS NOT NULL;
|
||||
INSERT INTO chat_log(type, operate, pid, ai_modal_id, messages, start_time, finish_time, token_usage, reasoning_content)
|
||||
SELECT '0',
|
||||
'1',
|
||||
id,
|
||||
ai_modal_id,
|
||||
safe_jsonb_cast(full_chart_message),
|
||||
create_time,
|
||||
finish_time,
|
||||
safe_jsonb_cast(token_chart),
|
||||
safe_jsonb_cast(chart_answer)->>'reasoning_content'
|
||||
FROM chat_record
|
||||
WHERE full_chart_message IS NOT NULL;
|
||||
INSERT INTO chat_log(type, operate, pid, ai_modal_id, messages, start_time, finish_time, token_usage, reasoning_content)
|
||||
SELECT '0',
|
||||
'2',
|
||||
id,
|
||||
ai_modal_id,
|
||||
safe_jsonb_cast(full_analysis_message),
|
||||
create_time,
|
||||
finish_time,
|
||||
safe_jsonb_cast(token_analysis),
|
||||
safe_jsonb_cast(analysis)->>'reasoning_content'
|
||||
FROM chat_record
|
||||
WHERE full_analysis_message IS NOT NULL;
|
||||
INSERT INTO chat_log(type, operate, pid, ai_modal_id, messages, start_time, finish_time, token_usage, reasoning_content)
|
||||
SELECT '0',
|
||||
'3',
|
||||
id,
|
||||
ai_modal_id,
|
||||
safe_jsonb_cast(full_predict_message),
|
||||
create_time,
|
||||
finish_time,
|
||||
safe_jsonb_cast(token_predict),
|
||||
safe_jsonb_cast(predict)->>'reasoning_content'
|
||||
FROM chat_record
|
||||
WHERE full_predict_message IS NOT NULL;
|
||||
INSERT INTO chat_log(type, operate, pid, ai_modal_id, messages, start_time, finish_time, token_usage, reasoning_content)
|
||||
SELECT '0',
|
||||
'4',
|
||||
id,
|
||||
ai_modal_id,
|
||||
safe_jsonb_cast(full_recommended_question_message),
|
||||
create_time,
|
||||
finish_time,
|
||||
safe_jsonb_cast(token_recommended_question),
|
||||
safe_jsonb_cast(recommended_question_answer)->>'reasoning_content'
|
||||
FROM chat_record
|
||||
WHERE full_recommended_question_message IS NOT NULL;
|
||||
INSERT INTO chat_log(type, operate, pid, ai_modal_id, messages, start_time, finish_time, token_usage, reasoning_content)
|
||||
SELECT '0',
|
||||
'6',
|
||||
id,
|
||||
ai_modal_id,
|
||||
safe_jsonb_cast(full_select_datasource_message),
|
||||
create_time,
|
||||
finish_time,
|
||||
safe_jsonb_cast(token_select_datasource_question),
|
||||
safe_jsonb_cast(datasource_select_answer)->>'reasoning_content'
|
||||
FROM chat_record
|
||||
WHERE full_select_datasource_message IS NOT NULL;
|
||||
|
||||
'''
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('chat_log',
|
||||
sa.Column('id', sa.BigInteger(), sa.Identity(always=True), nullable=False),
|
||||
sa.Column('type', sa.Enum('0', name='typeenum', native_enum=False, length=3), nullable=True),
|
||||
sa.Column('operate', sa.Enum('0', '1', '2', '3', '4', '5', '6', name='operationenum', native_enum=False, length=3), nullable=True),
|
||||
sa.Column('pid', sa.BigInteger(), nullable=True),
|
||||
sa.Column('ai_modal_id', sa.BigInteger(), nullable=True),
|
||||
sa.Column('base_modal', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
|
||||
sa.Column('messages', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('reasoning_content', sa.Text(), nullable=True),
|
||||
sa.Column('start_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('finish_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('token_usage', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
op.execute(sql)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
|
||||
op.drop_table('chat_log')
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,51 @@
|
||||
"""038_remove_chat_record_cloumns
|
||||
|
||||
Revision ID: fc23c4f3e755
|
||||
Revises: 68a06302cf70
|
||||
Create Date: 2025-08-21 14:34:59.149410
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel.sql.sqltypes
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'fc23c4f3e755'
|
||||
down_revision = '68a06302cf70'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('chat_record', 'token_predict')
|
||||
op.drop_column('chat_record', 'token_select_datasource_question')
|
||||
op.drop_column('chat_record', 'token_sql')
|
||||
op.drop_column('chat_record', 'full_analysis_message')
|
||||
op.drop_column('chat_record', 'full_recommended_question_message')
|
||||
op.drop_column('chat_record', 'token_chart')
|
||||
op.drop_column('chat_record', 'full_predict_message')
|
||||
op.drop_column('chat_record', 'full_chart_message')
|
||||
op.drop_column('chat_record', 'full_sql_message')
|
||||
op.drop_column('chat_record', 'full_select_datasource_message')
|
||||
op.drop_column('chat_record', 'token_recommended_question')
|
||||
op.drop_column('chat_record', 'token_analysis')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('chat_record', sa.Column('token_analysis', sa.VARCHAR(length=256), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('token_recommended_question', sa.VARCHAR(length=256), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('full_select_datasource_message', sa.TEXT(), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('full_sql_message', sa.TEXT(), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('full_chart_message', sa.TEXT(), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('full_predict_message', sa.TEXT(), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('token_chart', sa.VARCHAR(length=256), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('full_recommended_question_message', sa.TEXT(), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('full_analysis_message', sa.TEXT(), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('token_sql', sa.VARCHAR(length=256), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('token_select_datasource_question', sa.VARCHAR(length=256), autoincrement=False, nullable=True))
|
||||
op.add_column('chat_record', sa.Column('token_predict', sa.VARCHAR(length=256), autoincrement=False, nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
+165
-141
@@ -4,8 +4,10 @@ from typing import List
|
||||
import orjson
|
||||
import sqlparse
|
||||
from sqlalchemy import and_, select, update
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from apps.chat.models.chat_model import Chat, ChatRecord, CreateChat, ChatInfo, RenameChat, ChatQuestion
|
||||
from apps.chat.models.chat_model import Chat, ChatRecord, CreateChat, ChatInfo, RenameChat, ChatQuestion, ChatLog, \
|
||||
TypeEnum, OperationEnum, ChatRecordResult
|
||||
from apps.datasource.models.datasource import CoreDatasource
|
||||
from apps.system.crud.assistant import AssistantOutDsFactory
|
||||
from common.core.deps import CurrentAssistant, SessionDep, CurrentUser
|
||||
@@ -95,7 +97,10 @@ def get_chat_with_records_with_data(session: SessionDep, chart_id: int, current_
|
||||
current_assistant: CurrentAssistant) -> ChatInfo:
|
||||
return get_chat_with_records(session, chart_id, current_user, current_assistant, True)
|
||||
|
||||
|
||||
dynamic_ds_types = [1, 3]
|
||||
|
||||
|
||||
def get_chat_with_records(session: SessionDep, chart_id: int, current_user: CurrentUser,
|
||||
current_assistant: CurrentAssistant, with_data: bool = False) -> ChatInfo:
|
||||
chat = session.get(Chat, chart_id)
|
||||
@@ -118,13 +123,36 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr
|
||||
chat_info.datasource_name = ds.name
|
||||
chat_info.ds_type = ds.type
|
||||
|
||||
stmt = select(ChatRecord.id, ChatRecord.chat_id, ChatRecord.create_time, ChatRecord.finish_time,
|
||||
ChatRecord.question, ChatRecord.sql_answer, ChatRecord.sql,
|
||||
ChatRecord.chart_answer, ChatRecord.chart, ChatRecord.analysis, ChatRecord.predict,
|
||||
ChatRecord.datasource_select_answer, ChatRecord.analysis_record_id, ChatRecord.predict_record_id,
|
||||
ChatRecord.recommended_question, ChatRecord.first_chat,
|
||||
ChatRecord.finish, ChatRecord.error).where(
|
||||
and_(ChatRecord.create_by == current_user.id, ChatRecord.chat_id == chart_id)).order_by(ChatRecord.create_time)
|
||||
sql_alias_log = aliased(ChatLog)
|
||||
chart_alias_log = aliased(ChatLog)
|
||||
analysis_alias_log = aliased(ChatLog)
|
||||
predict_alias_log = aliased(ChatLog)
|
||||
|
||||
stmt = (select(ChatRecord.id, ChatRecord.chat_id, ChatRecord.create_time, ChatRecord.finish_time,
|
||||
ChatRecord.question, ChatRecord.sql_answer, ChatRecord.sql,
|
||||
ChatRecord.chart_answer, ChatRecord.chart, ChatRecord.analysis, ChatRecord.predict,
|
||||
ChatRecord.datasource_select_answer, ChatRecord.analysis_record_id, ChatRecord.predict_record_id,
|
||||
ChatRecord.recommended_question, ChatRecord.first_chat,
|
||||
ChatRecord.finish, ChatRecord.error,
|
||||
sql_alias_log.reasoning_content.label('sql_reasoning_content'),
|
||||
chart_alias_log.reasoning_content.label('chart_reasoning_content'),
|
||||
analysis_alias_log.reasoning_content.label('analysis_reasoning_content'),
|
||||
predict_alias_log.reasoning_content.label('predict_reasoning_content')
|
||||
)
|
||||
.outerjoin(sql_alias_log, and_(sql_alias_log.pid == ChatRecord.id,
|
||||
sql_alias_log.type == TypeEnum.CHAT,
|
||||
sql_alias_log.operate == OperationEnum.GENERATE_SQL))
|
||||
.outerjoin(chart_alias_log, and_(chart_alias_log.pid == ChatRecord.id,
|
||||
chart_alias_log.type == TypeEnum.CHAT,
|
||||
chart_alias_log.operate == OperationEnum.GENERATE_CHART))
|
||||
.outerjoin(analysis_alias_log, and_(analysis_alias_log.pid == ChatRecord.id,
|
||||
analysis_alias_log.type == TypeEnum.CHAT,
|
||||
analysis_alias_log.operate == OperationEnum.ANALYSIS))
|
||||
.outerjoin(predict_alias_log, and_(predict_alias_log.pid == ChatRecord.id,
|
||||
predict_alias_log.type == TypeEnum.CHAT,
|
||||
predict_alias_log.operate == OperationEnum.PREDICT_DATA))
|
||||
.where(and_(ChatRecord.create_by == current_user.id, ChatRecord.chat_id == chart_id)).order_by(
|
||||
ChatRecord.create_time))
|
||||
if with_data:
|
||||
stmt = select(ChatRecord.id, ChatRecord.chat_id, ChatRecord.create_time, ChatRecord.finish_time,
|
||||
ChatRecord.question, ChatRecord.sql_answer, ChatRecord.sql,
|
||||
@@ -136,28 +164,35 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr
|
||||
ChatRecord.create_time)
|
||||
|
||||
result = session.execute(stmt).all()
|
||||
record_list: list[ChatRecord] = []
|
||||
record_list: list[ChatRecordResult] = []
|
||||
for row in result:
|
||||
if not with_data:
|
||||
record_list.append(
|
||||
ChatRecord(id=row.id, chat_id=row.chat_id, create_time=row.create_time, finish_time=row.finish_time,
|
||||
question=row.question, sql_answer=row.sql_answer, sql=row.sql,
|
||||
chart_answer=row.chart_answer, chart=row.chart,
|
||||
analysis=row.analysis, predict=row.predict,
|
||||
datasource_select_answer=row.datasource_select_answer,
|
||||
analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id,
|
||||
recommended_question=row.recommended_question, first_chat=row.first_chat,
|
||||
finish=row.finish, error=row.error))
|
||||
ChatRecordResult(id=row.id, chat_id=row.chat_id, create_time=row.create_time,
|
||||
finish_time=row.finish_time,
|
||||
question=row.question, sql_answer=row.sql_answer, sql=row.sql,
|
||||
chart_answer=row.chart_answer, chart=row.chart,
|
||||
analysis=row.analysis, predict=row.predict,
|
||||
datasource_select_answer=row.datasource_select_answer,
|
||||
analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id,
|
||||
recommended_question=row.recommended_question, first_chat=row.first_chat,
|
||||
finish=row.finish, error=row.error,
|
||||
sql_reasoning_content=row.sql_reasoning_content,
|
||||
chart_reasoning_content=row.chart_reasoning_content,
|
||||
analysis_reasoning_content=row.analysis_reasoning_content,
|
||||
predict_reasoning_content=row.predict_reasoning_content,
|
||||
))
|
||||
else:
|
||||
record_list.append(
|
||||
ChatRecord(id=row.id, chat_id=row.chat_id, create_time=row.create_time, finish_time=row.finish_time,
|
||||
question=row.question, sql_answer=row.sql_answer, sql=row.sql,
|
||||
chart_answer=row.chart_answer, chart=row.chart,
|
||||
analysis=row.analysis, predict=row.predict,
|
||||
datasource_select_answer=row.datasource_select_answer,
|
||||
analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id,
|
||||
recommended_question=row.recommended_question, first_chat=row.first_chat,
|
||||
finish=row.finish, error=row.error, data=row.data, predict_data=row.predict_data))
|
||||
ChatRecordResult(id=row.id, chat_id=row.chat_id, create_time=row.create_time,
|
||||
finish_time=row.finish_time,
|
||||
question=row.question, sql_answer=row.sql_answer, sql=row.sql,
|
||||
chart_answer=row.chart_answer, chart=row.chart,
|
||||
analysis=row.analysis, predict=row.predict,
|
||||
datasource_select_answer=row.datasource_select_answer,
|
||||
analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id,
|
||||
recommended_question=row.recommended_question, first_chat=row.first_chat,
|
||||
finish=row.finish, error=row.error, data=row.data, predict_data=row.predict_data))
|
||||
|
||||
result = list(map(format_record, record_list))
|
||||
|
||||
@@ -166,27 +201,35 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr
|
||||
return chat_info
|
||||
|
||||
|
||||
def format_record(record: ChatRecord):
|
||||
def format_record(record: ChatRecordResult):
|
||||
_dict = record.model_dump()
|
||||
|
||||
if record.sql_answer and record.sql_answer.strip() != '' and record.sql_answer.strip()[0] == '{' and \
|
||||
record.sql_answer.strip()[-1] == '}':
|
||||
_obj = orjson.loads(record.sql_answer)
|
||||
_dict['sql_answer'] = _obj.get('reasoning_content')
|
||||
if record.sql_reasoning_content and record.sql_reasoning_content.strip() != '':
|
||||
_dict['sql_answer'] = record.sql_reasoning_content
|
||||
if record.chart_answer and record.chart_answer.strip() != '' and record.chart_answer.strip()[0] == '{' and \
|
||||
record.chart_answer.strip()[-1] == '}':
|
||||
_obj = orjson.loads(record.chart_answer)
|
||||
_dict['chart_answer'] = _obj.get('reasoning_content')
|
||||
if record.chart_reasoning_content and record.chart_reasoning_content.strip() != '':
|
||||
_dict['chart_answer'] = record.chart_reasoning_content
|
||||
if record.analysis and record.analysis.strip() != '' and record.analysis.strip()[0] == '{' and \
|
||||
record.analysis.strip()[-1] == '}':
|
||||
_obj = orjson.loads(record.analysis)
|
||||
_dict['analysis_thinking'] = _obj.get('reasoning_content')
|
||||
_dict['analysis'] = _obj.get('content')
|
||||
if record.analysis_reasoning_content and record.analysis_reasoning_content.strip() != '':
|
||||
_dict['analysis_thinking'] = record.analysis_reasoning_content
|
||||
if record.predict and record.predict.strip() != '' and record.predict.strip()[0] == '{' and record.predict.strip()[
|
||||
-1] == '}':
|
||||
_obj = orjson.loads(record.predict)
|
||||
_dict['predict'] = _obj.get('reasoning_content')
|
||||
_dict['predict_content'] = _obj.get('content')
|
||||
if record.predict_reasoning_content and record.predict_reasoning_content.strip() != '':
|
||||
_dict['predict'] = record.predict_reasoning_content
|
||||
if record.data and record.data.strip() != '':
|
||||
try:
|
||||
_obj = orjson.loads(record.data)
|
||||
@@ -208,19 +251,30 @@ def format_record(record: ChatRecord):
|
||||
return _dict
|
||||
|
||||
|
||||
def list_base_records(session: SessionDep, chart_id: int, current_user: CurrentUser) -> List[ChatRecord]:
|
||||
stmt = select(ChatRecord.id, ChatRecord.chat_id, ChatRecord.full_sql_message, ChatRecord.full_chart_message,
|
||||
ChatRecord.first_chat, ChatRecord.create_time).where(
|
||||
and_(ChatRecord.create_by == current_user.id, ChatRecord.chat_id == chart_id,
|
||||
ChatRecord.analysis_record_id.is_(None), ChatRecord.predict_record_id.is_(None))).order_by(
|
||||
ChatRecord.create_time)
|
||||
def list_generate_sql_logs(session: SessionDep, chart_id: int) -> List[ChatLog]:
|
||||
stmt = select(ChatLog).where(
|
||||
and_(ChatLog.pid.in_(select(ChatRecord.id).where(and_(ChatRecord.chat_id == chart_id))),
|
||||
ChatLog.type == TypeEnum.CHAT, ChatLog.operate == OperationEnum.GENERATE_SQL)).order_by(
|
||||
ChatLog.start_time)
|
||||
result = session.execute(stmt).all()
|
||||
record_list: List[ChatRecord] = []
|
||||
for r in result:
|
||||
record_list.append(
|
||||
ChatRecord(id=r.id, chat_id=r.chat_id, create_time=r.create_time, full_sql_message=r.full_sql_message,
|
||||
full_chart_message=r.full_chart_message, first_chat=r.first_chat))
|
||||
return record_list
|
||||
_list = []
|
||||
for row in result:
|
||||
for r in row:
|
||||
_list.append(ChatLog(**r.model_dump()))
|
||||
return _list
|
||||
|
||||
|
||||
def list_generate_chart_logs(session: SessionDep, chart_id: int) -> List[ChatLog]:
|
||||
stmt = select(ChatLog).where(
|
||||
and_(ChatLog.pid.in_(select(ChatRecord.id).where(and_(ChatRecord.chat_id == chart_id))),
|
||||
ChatLog.type == TypeEnum.CHAT, ChatLog.operate == OperationEnum.GENERATE_CHART)).order_by(
|
||||
ChatLog.start_time)
|
||||
result = session.execute(stmt).all()
|
||||
_list = []
|
||||
for row in result:
|
||||
for r in row:
|
||||
_list.append(ChatLog(**r.model_dump()))
|
||||
return _list
|
||||
|
||||
|
||||
def create_chat(session: SessionDep, current_user: CurrentUser, create_chat_obj: CreateChat,
|
||||
@@ -344,125 +398,117 @@ def save_analysis_predict_record(session: SessionDep, base_record: ChatRecord, a
|
||||
return result
|
||||
|
||||
|
||||
def save_full_sql_message(session: SessionDep, record_id: int, full_message: str) -> ChatRecord:
|
||||
return save_full_sql_message_and_answer(session=session, record_id=record_id, full_message=full_message, answer='')
|
||||
def start_log(session: SessionDep, ai_modal_id: int, ai_modal_name: str, operate: OperationEnum, record_id: int,
|
||||
full_message: list[dict]) -> ChatLog:
|
||||
log = ChatLog(type=TypeEnum.CHAT, operate=operate, pid=record_id, ai_modal_id=ai_modal_id, base_modal=ai_modal_name,
|
||||
messages=full_message, start_time=datetime.datetime.now())
|
||||
|
||||
result = ChatLog(**log.model_dump())
|
||||
|
||||
session.add(log)
|
||||
session.flush()
|
||||
session.refresh(log)
|
||||
result.id = log.id
|
||||
session.commit()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def save_full_sql_message_and_answer(session: SessionDep, record_id: int, answer: str, full_message: str,
|
||||
token_usage: dict = None) -> ChatRecord:
|
||||
def end_log(session: SessionDep, log: ChatLog, full_message: list[dict], reasoning_content: str = None,
|
||||
token_usage=None) -> ChatLog:
|
||||
if token_usage is None:
|
||||
token_usage = {}
|
||||
log.messages = full_message
|
||||
log.token_usage = token_usage
|
||||
log.finish_time = datetime.datetime.now()
|
||||
log.reasoning_content = reasoning_content if reasoning_content and len(reasoning_content.strip()) > 0 else None
|
||||
|
||||
stmt = update(ChatLog).where(and_(ChatLog.id == log.id)).values(
|
||||
messages=log.messages,
|
||||
token_usage=log.token_usage,
|
||||
finish_time=log.finish_time,
|
||||
reasoning_content=log.reasoning_content
|
||||
)
|
||||
session.execute(stmt)
|
||||
session.commit()
|
||||
|
||||
return log
|
||||
|
||||
|
||||
def save_sql_answer(session: SessionDep, record_id: int, answer: str) -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
record.full_sql_message = full_message
|
||||
record.sql_answer = answer
|
||||
|
||||
if token_usage:
|
||||
record.token_sql = orjson.dumps(token_usage).decode()
|
||||
|
||||
result = ChatRecord(**record.model_dump())
|
||||
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record.id)).values(
|
||||
full_sql_message=record.full_sql_message,
|
||||
sql_answer=record.sql_answer,
|
||||
token_sql=record.token_sql,
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record_id)).values(
|
||||
sql_answer=answer,
|
||||
)
|
||||
|
||||
session.execute(stmt)
|
||||
|
||||
session.commit()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def save_full_analysis_message_and_answer(session: SessionDep, record_id: int, answer: str,
|
||||
full_message: str, token_usage: dict = None) -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
record.full_analysis_message = full_message
|
||||
record.analysis = answer
|
||||
return record
|
||||
|
||||
if token_usage:
|
||||
record.token_analysis = orjson.dumps(token_usage).decode()
|
||||
|
||||
result = ChatRecord(**record.model_dump())
|
||||
def save_analysis_answer(session: SessionDep, record_id: int, answer: str = '') -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record.id)).values(
|
||||
full_analysis_message=record.full_analysis_message,
|
||||
analysis=record.analysis,
|
||||
token_analysis=record.token_analysis,
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record_id)).values(
|
||||
analysis=answer,
|
||||
)
|
||||
|
||||
session.execute(stmt)
|
||||
|
||||
session.commit()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def save_full_predict_message_and_answer(session: SessionDep, record_id: int, answer: str,
|
||||
full_message: str, data: str, token_usage: dict = None) -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
record.full_predict_message = full_message
|
||||
record.predict = answer
|
||||
record.predict_data = data
|
||||
return record
|
||||
|
||||
if token_usage:
|
||||
record.token_predict = orjson.dumps(token_usage).decode()
|
||||
|
||||
result = ChatRecord(**record.model_dump())
|
||||
def save_predict_answer(session: SessionDep, record_id: int, answer: str) -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record.id)).values(
|
||||
full_predict_message=record.full_predict_message,
|
||||
predict=record.predict,
|
||||
predict_data=record.predict_data,
|
||||
token_predict=record.token_predict
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record_id)).values(
|
||||
predict=answer,
|
||||
)
|
||||
|
||||
session.execute(stmt)
|
||||
|
||||
session.commit()
|
||||
|
||||
return result
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
return record
|
||||
|
||||
|
||||
def save_full_select_datasource_message_and_answer(session: SessionDep, record_id: int, answer: str,
|
||||
full_message: str, datasource: int = None,
|
||||
engine_type: str = None, token_usage: dict = None) -> ChatRecord:
|
||||
def save_select_datasource_answer(session: SessionDep, record_id: int, answer: str,
|
||||
datasource: int = None, engine_type: str = None) -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
record.full_select_datasource_message = full_message
|
||||
record.datasource_select_answer = answer
|
||||
|
||||
if datasource:
|
||||
record.datasource = datasource
|
||||
record.engine_type = engine_type
|
||||
|
||||
if token_usage:
|
||||
record.token_select_datasource_question = orjson.dumps(token_usage).decode()
|
||||
|
||||
result = ChatRecord(**record.model_dump())
|
||||
|
||||
if datasource:
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record.id)).values(
|
||||
full_select_datasource_message=record.full_select_datasource_message,
|
||||
datasource_select_answer=record.datasource_select_answer,
|
||||
token_select_datasource_question=record.token_select_datasource_question,
|
||||
datasource=record.datasource,
|
||||
engine_type=record.engine_type,
|
||||
)
|
||||
else:
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record.id)).values(
|
||||
full_select_datasource_message=record.full_select_datasource_message,
|
||||
datasource_select_answer=record.datasource_select_answer,
|
||||
token_select_datasource_question=record.token_select_datasource_question,
|
||||
)
|
||||
|
||||
session.execute(stmt)
|
||||
@@ -472,16 +518,12 @@ def save_full_select_datasource_message_and_answer(session: SessionDep, record_i
|
||||
return result
|
||||
|
||||
|
||||
def save_full_recommend_question_message_and_answer(session: SessionDep, record_id: int, answer: dict = None,
|
||||
full_message: str = '[]', token_usage: dict = None) -> ChatRecord:
|
||||
def save_recommend_question_answer(session: SessionDep, record_id: int,
|
||||
answer: dict = None) -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
record.full_recommended_question_message = full_message
|
||||
|
||||
if answer:
|
||||
record.recommended_question_answer = orjson.dumps(answer).decode()
|
||||
recommended_question_answer = orjson.dumps(answer).decode()
|
||||
|
||||
json_str = '[]'
|
||||
if answer and answer.get('content') and answer.get('content') != '':
|
||||
@@ -492,25 +534,22 @@ def save_full_recommend_question_message_and_answer(session: SessionDep, record_
|
||||
json_str = '[]'
|
||||
except Exception as e:
|
||||
pass
|
||||
record.recommended_question = json_str
|
||||
recommended_question = json_str
|
||||
|
||||
if token_usage:
|
||||
record.token_recommended_question = orjson.dumps(token_usage).decode()
|
||||
|
||||
result = ChatRecord(**record.model_dump())
|
||||
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record.id)).values(
|
||||
full_recommended_question_message=record.full_recommended_question_message,
|
||||
recommended_question_answer=record.recommended_question_answer,
|
||||
recommended_question=record.recommended_question,
|
||||
token_recommended_question=record.token_recommended_question
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record_id)).values(
|
||||
recommended_question_answer=recommended_question_answer,
|
||||
recommended_question=recommended_question,
|
||||
)
|
||||
|
||||
session.execute(stmt)
|
||||
|
||||
session.commit()
|
||||
|
||||
return result
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
record.recommended_question_answer = recommended_question_answer
|
||||
record.recommended_question = recommended_question
|
||||
|
||||
return record
|
||||
|
||||
|
||||
def save_sql(session: SessionDep, record_id: int, sql: str) -> ChatRecord:
|
||||
@@ -534,36 +573,21 @@ def save_sql(session: SessionDep, record_id: int, sql: str) -> ChatRecord:
|
||||
return result
|
||||
|
||||
|
||||
def save_full_chart_message(session: SessionDep, record_id: int, full_message: str) -> ChatRecord:
|
||||
return save_full_chart_message_and_answer(session=session, record_id=record_id, full_message=full_message,
|
||||
answer='')
|
||||
|
||||
|
||||
def save_full_chart_message_and_answer(session: SessionDep, record_id: int, answer: str,
|
||||
full_message: str, token_usage: dict = None) -> ChatRecord:
|
||||
def save_chart_answer(session: SessionDep, record_id: int, answer: str) -> ChatRecord:
|
||||
if not record_id:
|
||||
raise Exception("Record id cannot be None")
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
record.full_chart_message = full_message
|
||||
record.chart_answer = answer
|
||||
|
||||
if token_usage:
|
||||
record.token_chart = orjson.dumps(token_usage).decode()
|
||||
|
||||
result = ChatRecord(**record.model_dump())
|
||||
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record.id)).values(
|
||||
full_chart_message=record.full_chart_message,
|
||||
chart_answer=record.chart_answer,
|
||||
token_chart=record.token_chart
|
||||
stmt = update(ChatRecord).where(and_(ChatRecord.id == record_id)).values(
|
||||
chart_answer=answer,
|
||||
)
|
||||
|
||||
session.execute(stmt)
|
||||
|
||||
session.commit()
|
||||
|
||||
return result
|
||||
record = get_chat_record_by_id(session, record_id)
|
||||
|
||||
return record
|
||||
|
||||
|
||||
def save_chart(session: SessionDep, record_id: int, chart: str) -> ChatRecord:
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import Body
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import Column, Integer, Text, BigInteger, DateTime, Identity, Boolean
|
||||
from sqlalchemy import Enum as SQLAlchemyEnum
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlmodel import SQLModel, Field
|
||||
|
||||
from apps.template.filter.generator import get_permissions_template
|
||||
@@ -16,6 +19,47 @@ from apps.template.generate_sql.generator import get_sql_template
|
||||
from apps.template.select_datasource.generator import get_datasource_template
|
||||
|
||||
|
||||
def enum_values(enum_class: type[Enum]) -> list:
|
||||
"""Get values for enum."""
|
||||
return [status.value for status in enum_class]
|
||||
|
||||
|
||||
class TypeEnum(Enum):
|
||||
CHAT = "0"
|
||||
|
||||
|
||||
# TODO other usage
|
||||
|
||||
class OperationEnum(Enum):
|
||||
GENERATE_SQL = '0'
|
||||
GENERATE_CHART = '1'
|
||||
ANALYSIS = '2'
|
||||
PREDICT_DATA = '3'
|
||||
GENERATE_RECOMMENDED_QUESTIONS = '4'
|
||||
GENERATE_SQL_WITH_PERMISSIONS = '5'
|
||||
CHOOSE_DATASOURCE = '6'
|
||||
GENERATE_DYNAMIC_SQL = '7'
|
||||
|
||||
|
||||
# TODO choose table / check connection / generate description
|
||||
|
||||
class ChatLog(SQLModel, table=True):
|
||||
__tablename__ = "chat_log"
|
||||
id: Optional[int] = Field(sa_column=Column(BigInteger, Identity(always=True), primary_key=True))
|
||||
type: TypeEnum = Field(
|
||||
sa_column=Column(SQLAlchemyEnum(TypeEnum, native_enum=False, values_callable=enum_values, length=3)))
|
||||
operate: OperationEnum = Field(
|
||||
sa_column=Column(SQLAlchemyEnum(OperationEnum, native_enum=False, values_callable=enum_values, length=3)))
|
||||
pid: Optional[int] = Field(sa_column=Column(BigInteger, nullable=True))
|
||||
ai_modal_id: Optional[int] = Field(sa_column=Column(BigInteger))
|
||||
base_modal: Optional[str] = Field(max_length=255)
|
||||
messages: Optional[list[dict]] = Field(sa_column=Column(JSONB))
|
||||
reasoning_content: Optional[str | None] = Field(sa_column=Column(Text, nullable=True))
|
||||
start_time: datetime = Field(sa_column=Column(DateTime(timezone=False), nullable=True))
|
||||
finish_time: datetime = Field(sa_column=Column(DateTime(timezone=False), nullable=True))
|
||||
token_usage: Optional[dict | None | int] = Field(sa_column=Column(JSONB))
|
||||
|
||||
|
||||
class Chat(SQLModel, table=True):
|
||||
__tablename__ = "chat"
|
||||
id: Optional[int] = Field(sa_column=Column(BigInteger, Identity(always=True), primary_key=True))
|
||||
@@ -54,24 +98,40 @@ class ChatRecord(SQLModel, table=True):
|
||||
recommended_question_answer: str = Field(sa_column=Column(Text, nullable=True))
|
||||
recommended_question: str = Field(sa_column=Column(Text, nullable=True))
|
||||
datasource_select_answer: str = Field(sa_column=Column(Text, nullable=True))
|
||||
full_sql_message: str = Field(sa_column=Column(Text, nullable=True))
|
||||
token_sql: str = Field(max_length=256, nullable=True)
|
||||
full_chart_message: str = Field(sa_column=Column(Text, nullable=True))
|
||||
token_chart: str = Field(max_length=256, nullable=True)
|
||||
full_analysis_message: str = Field(sa_column=Column(Text, nullable=True))
|
||||
token_analysis: str = Field(max_length=256, nullable=True)
|
||||
full_predict_message: str = Field(sa_column=Column(Text, nullable=True))
|
||||
token_predict: str = Field(max_length=256, nullable=True)
|
||||
full_recommended_question_message: str = Field(sa_column=Column(Text, nullable=True))
|
||||
token_recommended_question: str = Field(max_length=256, nullable=True)
|
||||
full_select_datasource_message: str = Field(sa_column=Column(Text, nullable=True))
|
||||
token_select_datasource_question: str = Field(max_length=256, nullable=True)
|
||||
finish: bool = Field(sa_column=Column(Boolean, nullable=True, default=False))
|
||||
error: str = Field(sa_column=Column(Text, nullable=True))
|
||||
analysis_record_id: int = Field(sa_column=Column(BigInteger, nullable=True))
|
||||
predict_record_id: int = Field(sa_column=Column(BigInteger, nullable=True))
|
||||
|
||||
|
||||
class ChatRecordResult(BaseModel):
|
||||
id: Optional[int] = None
|
||||
chat_id: Optional[int] = None
|
||||
ai_modal_id: Optional[int] = None
|
||||
first_chat: bool = False
|
||||
create_time: Optional[datetime] = None
|
||||
finish_time: Optional[datetime] = None
|
||||
question: Optional[str] = None
|
||||
sql_answer: Optional[str] = None
|
||||
sql: Optional[str] = None
|
||||
data: Optional[str] = None
|
||||
chart_answer: Optional[str] = None
|
||||
chart: Optional[str] = None
|
||||
analysis: Optional[str] = None
|
||||
predict: Optional[str] = None
|
||||
predict_data: Optional[str] = None
|
||||
recommended_question: Optional[str] = None
|
||||
datasource_select_answer: Optional[str] = None
|
||||
finish: Optional[bool] = None
|
||||
error: Optional[str] = None
|
||||
analysis_record_id: Optional[int] = None
|
||||
predict_record_id: Optional[int] = None
|
||||
sql_reasoning_content: Optional[str] = None
|
||||
chart_reasoning_content: Optional[str] = None
|
||||
analysis_reasoning_content: Optional[str] = None
|
||||
predict_reasoning_content: Optional[str] = None
|
||||
|
||||
|
||||
class CreateChat(BaseModel):
|
||||
id: int = None
|
||||
question: str = None
|
||||
@@ -100,6 +160,7 @@ class ChatInfo(BaseModel):
|
||||
|
||||
class AiModelQuestion(BaseModel):
|
||||
ai_modal_id: int = None
|
||||
ai_modal_name: str = None # Specific model name
|
||||
engine: str = ""
|
||||
db_schema: str = ""
|
||||
sql: str = ""
|
||||
|
||||
+215
-159
@@ -18,13 +18,13 @@ from sqlalchemy.orm import sessionmaker
|
||||
from sqlmodel import create_engine, Session
|
||||
|
||||
from apps.ai_model.model_factory import LLMConfig, LLMFactory, get_default_config
|
||||
from apps.chat.curd.chat import save_question, save_full_sql_message, save_full_sql_message_and_answer, save_sql, \
|
||||
save_error_message, save_sql_exec_data, save_full_chart_message, save_full_chart_message_and_answer, save_chart, \
|
||||
finish_record, save_full_analysis_message_and_answer, save_full_predict_message_and_answer, save_predict_data, \
|
||||
save_full_select_datasource_message_and_answer, save_full_recommend_question_message_and_answer, \
|
||||
get_old_questions, save_analysis_predict_record, list_base_records, rename_chat, get_chart_config, \
|
||||
get_chat_chart_data
|
||||
from apps.chat.models.chat_model import ChatQuestion, ChatRecord, Chat, RenameChat
|
||||
from apps.chat.curd.chat import save_question, save_sql_answer, save_sql, \
|
||||
save_error_message, save_sql_exec_data, save_chart_answer, save_chart, \
|
||||
finish_record, save_analysis_answer, save_predict_answer, save_predict_data, \
|
||||
save_select_datasource_answer, save_recommend_question_answer, \
|
||||
get_old_questions, save_analysis_predict_record, rename_chat, get_chart_config, \
|
||||
get_chat_chart_data, list_generate_sql_logs, list_generate_chart_logs, start_log, end_log
|
||||
from apps.chat.models.chat_model import ChatQuestion, ChatRecord, Chat, RenameChat, ChatLog, OperationEnum
|
||||
from apps.datasource.crud.datasource import get_table_schema
|
||||
from apps.datasource.crud.permission import get_row_permission_filters, is_normal_user
|
||||
from apps.datasource.models.datasource import CoreDatasource
|
||||
@@ -38,12 +38,13 @@ from common.utils.utils import SQLBotLogUtil, extract_nested_json, prepare_for_o
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
base_message_count_limit = 5
|
||||
base_message_count_limit = 6
|
||||
|
||||
executor = ThreadPoolExecutor(max_workers=200)
|
||||
|
||||
dynamic_ds_types = [1, 3]
|
||||
|
||||
|
||||
class LLMService:
|
||||
ds: CoreDatasource
|
||||
chat_question: ChatQuestion
|
||||
@@ -52,13 +53,18 @@ class LLMService:
|
||||
llm: BaseChatModel
|
||||
sql_message: List[Union[BaseMessage, dict[str, Any]]] = []
|
||||
chart_message: List[Union[BaseMessage, dict[str, Any]]] = []
|
||||
history_records: List[ChatRecord] = []
|
||||
|
||||
session: Session
|
||||
current_user: CurrentUser
|
||||
current_assistant: Optional[CurrentAssistant] = None
|
||||
out_ds_instance: Optional[AssistantOutDs] = None
|
||||
change_title: bool = False
|
||||
|
||||
generate_sql_logs: List[ChatLog] = []
|
||||
generate_chart_logs: List[ChatLog] = []
|
||||
|
||||
current_logs: dict[OperationEnum, ChatLog] = {}
|
||||
|
||||
chunk_list: List[str] = []
|
||||
future: Future
|
||||
|
||||
@@ -94,12 +100,10 @@ class LLMService:
|
||||
chat_question.engine = ds.type_name if ds.type != 'excel' else 'PostgreSQL'
|
||||
chat_question.db_schema = get_table_schema(session=self.session, current_user=current_user, ds=ds)
|
||||
|
||||
history_records: List[ChatRecord] = list(
|
||||
map(lambda x: ChatRecord(**x.model_dump()), filter(lambda r: True if r.first_chat != True else False,
|
||||
list_base_records(session=self.session,
|
||||
current_user=current_user,
|
||||
chart_id=chat_id))))
|
||||
self.change_title = len(history_records) == 0
|
||||
self.generate_sql_logs = list_generate_sql_logs(session=self.session, chart_id=chat_id)
|
||||
self.generate_chart_logs = list_generate_chart_logs(session=self.session, chart_id=chat_id)
|
||||
|
||||
self.change_title = len(self.generate_sql_logs) == 0
|
||||
|
||||
chat_question.lang = get_lang_name(current_user.language)
|
||||
|
||||
@@ -114,13 +118,12 @@ class LLMService:
|
||||
del self.config.additional_params['extra_body']['enable_thinking']
|
||||
|
||||
self.chat_question.ai_modal_id = self.config.model_id
|
||||
self.chat_question.ai_modal_name = self.config.model_name
|
||||
|
||||
# Create LLM instance through factory
|
||||
llm_instance = LLMFactory.create_llm(self.config)
|
||||
self.llm = llm_instance.llm
|
||||
|
||||
self.history_records = history_records
|
||||
|
||||
self.init_messages()
|
||||
|
||||
def is_running(self, timeout=0.5):
|
||||
@@ -134,21 +137,8 @@ class LLMService:
|
||||
return True
|
||||
|
||||
def init_messages(self):
|
||||
# self.agent_executor = create_react_agent(self.llm)
|
||||
last_sql_messages = list(
|
||||
filter(lambda r: True if r.full_sql_message is not None and r.full_sql_message.strip() != '' else False,
|
||||
self.history_records))
|
||||
last_sql_message_str = "[]" if last_sql_messages is None or len(last_sql_messages) == 0 else last_sql_messages[
|
||||
-1].full_sql_message
|
||||
|
||||
last_chart_messages = list(
|
||||
filter(
|
||||
lambda r: True if r.full_chart_message is not None and r.full_chart_message.strip() != '' else False,
|
||||
self.history_records))
|
||||
last_chart_message_str = "[]" if last_chart_messages is None or len(last_chart_messages) == 0 else \
|
||||
last_chart_messages[-1].full_chart_message
|
||||
|
||||
last_sql_messages: List[dict[str, Any]] = orjson.loads(last_sql_message_str)
|
||||
last_sql_messages: List[dict[str, Any]] = self.generate_sql_logs[-1].messages if len(
|
||||
self.generate_sql_logs) > 0 else []
|
||||
|
||||
# todo maybe can configure
|
||||
count_limit = 0 - base_message_count_limit
|
||||
@@ -167,7 +157,8 @@ class LLMService:
|
||||
_msg = AIMessage(content=last_sql_message['content'])
|
||||
self.sql_message.append(_msg)
|
||||
|
||||
last_chart_messages: List[dict[str, Any]] = orjson.loads(last_chart_message_str)
|
||||
last_chart_messages: List[dict[str, Any]] = self.generate_chart_logs[-1].messages if len(
|
||||
self.generate_chart_logs) > 0 else []
|
||||
|
||||
self.chart_message = []
|
||||
# add sys prompt
|
||||
@@ -177,11 +168,11 @@ class LLMService:
|
||||
# limit count
|
||||
for last_chart_message in last_chart_messages:
|
||||
_msg: BaseMessage
|
||||
if last_chart_message['type'] == 'human':
|
||||
_msg = HumanMessage(content=last_chart_message['content'])
|
||||
if last_chart_message.get('type') == 'human':
|
||||
_msg = HumanMessage(content=last_chart_message.get('content'))
|
||||
self.chart_message.append(_msg)
|
||||
elif last_chart_message['type'] == 'ai':
|
||||
_msg = AIMessage(content=last_chart_message['content'])
|
||||
elif last_chart_message.get('type') == 'ai':
|
||||
_msg = AIMessage(content=last_chart_message.get('content'))
|
||||
self.chart_message.append(_msg)
|
||||
|
||||
def init_record(self) -> ChatRecord:
|
||||
@@ -222,11 +213,16 @@ class LLMService:
|
||||
analysis_msg.append(SystemMessage(content=self.chat_question.analysis_sys_question()))
|
||||
analysis_msg.append(HumanMessage(content=self.chat_question.analysis_user_question()))
|
||||
|
||||
self.record = save_full_analysis_message_and_answer(session=self.session, record_id=self.record.id, answer='',
|
||||
full_message=orjson.dumps([{'type': msg.type,
|
||||
'content': msg.content} for msg
|
||||
in
|
||||
analysis_msg]).decode())
|
||||
self.current_logs[OperationEnum.ANALYSIS] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.ANALYSIS,
|
||||
record_id=self.record.id,
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content} for
|
||||
msg
|
||||
in analysis_msg])
|
||||
full_thinking_text = ''
|
||||
full_analysis_text = ''
|
||||
res = self.llm.stream(analysis_msg)
|
||||
@@ -247,14 +243,18 @@ class LLMService:
|
||||
get_token_usage(chunk, token_usage)
|
||||
|
||||
analysis_msg.append(AIMessage(full_analysis_text))
|
||||
self.record = save_full_analysis_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
token_usage=token_usage,
|
||||
answer=orjson.dumps({'content': full_analysis_text,
|
||||
'reasoning_content': full_thinking_text}).decode(),
|
||||
full_message=orjson.dumps([{'type': msg.type,
|
||||
'content': msg.content} for msg
|
||||
in
|
||||
analysis_msg]).decode())
|
||||
|
||||
self.current_logs[OperationEnum.ANALYSIS] = end_log(session=self.session,
|
||||
log=self.current_logs[
|
||||
OperationEnum.ANALYSIS],
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg in analysis_msg],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
self.record = save_analysis_answer(session=self.session, record_id=self.record.id,
|
||||
answer=orjson.dumps({'content': full_analysis_text}).decode())
|
||||
|
||||
def generate_predict(self):
|
||||
fields = self.get_fields_from_chart()
|
||||
@@ -265,12 +265,16 @@ class LLMService:
|
||||
predict_msg.append(SystemMessage(content=self.chat_question.predict_sys_question()))
|
||||
predict_msg.append(HumanMessage(content=self.chat_question.predict_user_question()))
|
||||
|
||||
self.record = save_full_predict_message_and_answer(session=self.session, record_id=self.record.id, answer='',
|
||||
data='',
|
||||
full_message=orjson.dumps([{'type': msg.type,
|
||||
'content': msg.content} for msg
|
||||
in
|
||||
predict_msg]).decode())
|
||||
self.current_logs[OperationEnum.PREDICT_DATA] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.PREDICT_DATA,
|
||||
record_id=self.record.id,
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content} for
|
||||
msg
|
||||
in predict_msg])
|
||||
full_thinking_text = ''
|
||||
full_predict_text = ''
|
||||
res = self.llm.stream(predict_msg)
|
||||
@@ -291,15 +295,17 @@ class LLMService:
|
||||
get_token_usage(chunk, token_usage)
|
||||
|
||||
predict_msg.append(AIMessage(full_predict_text))
|
||||
self.record = save_full_predict_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
token_usage=token_usage,
|
||||
answer=orjson.dumps({'content': full_predict_text,
|
||||
'reasoning_content': full_thinking_text}).decode(),
|
||||
data='',
|
||||
full_message=orjson.dumps([{'type': msg.type,
|
||||
'content': msg.content} for msg
|
||||
in
|
||||
predict_msg]).decode())
|
||||
self.record = save_predict_answer(session=self.session, record_id=self.record.id,
|
||||
answer=orjson.dumps({'content': full_predict_text}).decode())
|
||||
self.current_logs[OperationEnum.PREDICT_DATA] = end_log(session=self.session,
|
||||
log=self.current_logs[
|
||||
OperationEnum.PREDICT_DATA],
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg in predict_msg],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
|
||||
def generate_recommend_questions_task(self):
|
||||
|
||||
@@ -316,12 +322,16 @@ class LLMService:
|
||||
guess_msg.append(
|
||||
HumanMessage(content=self.chat_question.guess_user_question(orjson.dumps(old_questions).decode())))
|
||||
|
||||
self.record = save_full_recommend_question_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
full_message=orjson.dumps([{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg
|
||||
in
|
||||
guess_msg]).decode())
|
||||
self.current_logs[OperationEnum.GENERATE_RECOMMENDED_QUESTIONS] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.GENERATE_RECOMMENDED_QUESTIONS,
|
||||
record_id=self.record.id,
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content} for
|
||||
msg
|
||||
in guess_msg])
|
||||
full_thinking_text = ''
|
||||
full_guess_text = ''
|
||||
token_usage = {}
|
||||
@@ -342,15 +352,19 @@ class LLMService:
|
||||
get_token_usage(chunk, token_usage)
|
||||
|
||||
guess_msg.append(AIMessage(full_guess_text))
|
||||
self.record = save_full_recommend_question_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
token_usage=token_usage,
|
||||
answer={'content': full_guess_text,
|
||||
'reasoning_content': full_thinking_text},
|
||||
full_message=orjson.dumps([{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg
|
||||
in
|
||||
guess_msg]).decode())
|
||||
|
||||
self.current_logs[OperationEnum.GENERATE_RECOMMENDED_QUESTIONS] = end_log(session=self.session,
|
||||
log=self.current_logs[
|
||||
OperationEnum.GENERATE_RECOMMENDED_QUESTIONS],
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg in guess_msg],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
self.record = save_recommend_question_answer(session=self.session, record_id=self.record.id,
|
||||
answer={'content': full_guess_text})
|
||||
|
||||
yield {'recommended_question': self.record.recommended_question}
|
||||
|
||||
def select_datasource(self):
|
||||
@@ -376,6 +390,9 @@ class LLMService:
|
||||
ignore_auto_select = _ds_list and len(_ds_list) == 1
|
||||
# ignore auto select ds
|
||||
|
||||
full_thinking_text = ''
|
||||
full_text = ''
|
||||
|
||||
if not ignore_auto_select:
|
||||
_ds_list_dict = []
|
||||
for _ds in _ds_list:
|
||||
@@ -383,20 +400,15 @@ class LLMService:
|
||||
datasource_msg.append(
|
||||
HumanMessage(self.chat_question.datasource_user_question(orjson.dumps(_ds_list_dict).decode())))
|
||||
|
||||
history_msg = []
|
||||
if self.record.full_select_datasource_message and self.record.full_select_datasource_message.strip() != '':
|
||||
history_msg = orjson.loads(self.record.full_select_datasource_message)
|
||||
self.current_logs[OperationEnum.CHOOSE_DATASOURCE] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.CHOOSE_DATASOURCE,
|
||||
record_id=self.record.id,
|
||||
full_message=[{'type': msg.type,
|
||||
'content': msg.content} for
|
||||
msg in datasource_msg])
|
||||
|
||||
self.record = save_full_select_datasource_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
answer='',
|
||||
full_message=orjson.dumps(history_msg +
|
||||
[{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg
|
||||
in
|
||||
datasource_msg]).decode())
|
||||
full_thinking_text = ''
|
||||
full_text = ''
|
||||
token_usage = {}
|
||||
res = self.llm.stream(datasource_msg)
|
||||
for chunk in res:
|
||||
@@ -415,6 +427,15 @@ class LLMService:
|
||||
get_token_usage(chunk, token_usage)
|
||||
datasource_msg.append(AIMessage(full_text))
|
||||
|
||||
self.current_logs[OperationEnum.CHOOSE_DATASOURCE] = end_log(session=self.session,
|
||||
log=self.current_logs[
|
||||
OperationEnum.CHOOSE_DATASOURCE],
|
||||
full_message=[
|
||||
{'type': msg.type, 'content': msg.content}
|
||||
for msg in datasource_msg],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
|
||||
json_str = extract_nested_json(full_text)
|
||||
|
||||
_error: Exception | None = None
|
||||
@@ -460,17 +481,10 @@ class LLMService:
|
||||
_error = e
|
||||
|
||||
if not ignore_auto_select:
|
||||
self.record = save_full_select_datasource_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
answer=orjson.dumps({'content': full_text,
|
||||
'reasoning_content': full_thinking_text}).decode(),
|
||||
datasource=_datasource,
|
||||
engine_type=_engine_type,
|
||||
full_message=orjson.dumps(history_msg +
|
||||
[{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg
|
||||
in
|
||||
datasource_msg]).decode())
|
||||
self.record = save_select_datasource_answer(session=self.session, record_id=self.record.id,
|
||||
answer=orjson.dumps({'content': full_text}).decode(),
|
||||
datasource=_datasource,
|
||||
engine_type=_engine_type)
|
||||
self.init_messages()
|
||||
|
||||
if _error:
|
||||
@@ -479,10 +493,15 @@ class LLMService:
|
||||
def generate_sql(self):
|
||||
# append current question
|
||||
self.sql_message.append(HumanMessage(self.chat_question.sql_user_question()))
|
||||
self.record = save_full_sql_message(session=self.session, record_id=self.record.id,
|
||||
full_message=orjson.dumps(
|
||||
[{'type': msg.type, 'content': msg.content} for msg in
|
||||
self.sql_message]).decode())
|
||||
|
||||
self.current_logs[OperationEnum.GENERATE_SQL] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.GENERATE_SQL,
|
||||
record_id=self.record.id,
|
||||
full_message=[
|
||||
{'type': msg.type, 'content': msg.content} for msg
|
||||
in self.sql_message])
|
||||
full_thinking_text = ''
|
||||
full_sql_text = ''
|
||||
token_usage = {}
|
||||
@@ -503,24 +522,37 @@ class LLMService:
|
||||
get_token_usage(chunk, token_usage)
|
||||
|
||||
self.sql_message.append(AIMessage(full_sql_text))
|
||||
self.record = save_full_sql_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
token_usage=token_usage,
|
||||
answer=orjson.dumps({'content': full_sql_text,
|
||||
'reasoning_content': full_thinking_text}).decode(),
|
||||
full_message=orjson.dumps(
|
||||
[{'type': msg.type, 'content': msg.content} for msg in
|
||||
self.sql_message]).decode())
|
||||
|
||||
self.current_logs[OperationEnum.GENERATE_SQL] = end_log(session=self.session,
|
||||
log=self.current_logs[OperationEnum.GENERATE_SQL],
|
||||
full_message=[{'type': msg.type, 'content': msg.content}
|
||||
for msg in self.sql_message],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
self.record = save_sql_answer(session=self.session, record_id=self.record.id,
|
||||
answer=orjson.dumps({'content': full_sql_text}).decode())
|
||||
|
||||
def generate_with_sub_sql(self, sql, sub_mappings: list):
|
||||
sub_query = json.dumps(sub_mappings, ensure_ascii=False)
|
||||
self.chat_question.sql = sql
|
||||
self.chat_question.sub_query = sub_query
|
||||
msg: List[Union[BaseMessage, dict[str, Any]]] = []
|
||||
msg.append(SystemMessage(content=self.chat_question.dynamic_sys_question()))
|
||||
msg.append(HumanMessage(content=self.chat_question.dynamic_user_question()))
|
||||
dynamic_sql_msg: List[Union[BaseMessage, dict[str, Any]]] = []
|
||||
dynamic_sql_msg.append(SystemMessage(content=self.chat_question.dynamic_sys_question()))
|
||||
dynamic_sql_msg.append(HumanMessage(content=self.chat_question.dynamic_user_question()))
|
||||
|
||||
self.current_logs[OperationEnum.GENERATE_DYNAMIC_SQL] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.GENERATE_DYNAMIC_SQL,
|
||||
record_id=self.record.id,
|
||||
full_message=[{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for
|
||||
msg in dynamic_sql_msg])
|
||||
|
||||
full_thinking_text = ''
|
||||
full_dynamic_text = ''
|
||||
res = self.llm.stream(msg)
|
||||
res = self.llm.stream(dynamic_sql_msg)
|
||||
token_usage = {}
|
||||
for chunk in res:
|
||||
SQLBotLogUtil.info(chunk)
|
||||
@@ -533,6 +565,18 @@ class LLMService:
|
||||
full_dynamic_text += chunk.content
|
||||
get_token_usage(chunk, token_usage)
|
||||
|
||||
dynamic_sql_msg.append(AIMessage(full_dynamic_text))
|
||||
|
||||
self.current_logs[OperationEnum.GENERATE_DYNAMIC_SQL] = end_log(session=self.session,
|
||||
log=self.current_logs[
|
||||
OperationEnum.GENERATE_DYNAMIC_SQL],
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg in dynamic_sql_msg],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
|
||||
SQLBotLogUtil.info(full_dynamic_text)
|
||||
return full_dynamic_text
|
||||
|
||||
@@ -550,23 +594,23 @@ class LLMService:
|
||||
filter = json.dumps(filters, ensure_ascii=False)
|
||||
self.chat_question.sql = sql
|
||||
self.chat_question.filter = filter
|
||||
msg: List[Union[BaseMessage, dict[str, Any]]] = []
|
||||
msg.append(SystemMessage(content=self.chat_question.filter_sys_question()))
|
||||
msg.append(HumanMessage(content=self.chat_question.filter_user_question()))
|
||||
permission_sql_msg: List[Union[BaseMessage, dict[str, Any]]] = []
|
||||
permission_sql_msg.append(SystemMessage(content=self.chat_question.filter_sys_question()))
|
||||
permission_sql_msg.append(HumanMessage(content=self.chat_question.filter_user_question()))
|
||||
|
||||
history_msg = []
|
||||
# if self.record.full_analysis_message and self.record.full_analysis_message.strip() != '':
|
||||
# history_msg = orjson.loads(self.record.full_analysis_message)
|
||||
|
||||
# self.record = save_full_analysis_message_and_answer(session=self.session, record_id=self.record.id, answer='',
|
||||
# full_message=orjson.dumps(history_msg +
|
||||
# [{'type': msg.type,
|
||||
# 'content': msg.content} for msg
|
||||
# in
|
||||
# msg]).decode())
|
||||
self.current_logs[OperationEnum.GENERATE_SQL_WITH_PERMISSIONS] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.GENERATE_SQL_WITH_PERMISSIONS,
|
||||
record_id=self.record.id,
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content} for
|
||||
msg
|
||||
in permission_sql_msg])
|
||||
full_thinking_text = ''
|
||||
full_filter_text = ''
|
||||
res = self.llm.stream(msg)
|
||||
res = self.llm.stream(permission_sql_msg)
|
||||
token_usage = {}
|
||||
for chunk in res:
|
||||
SQLBotLogUtil.info(chunk)
|
||||
@@ -583,16 +627,18 @@ class LLMService:
|
||||
# yield {'content': chunk.content, 'reasoning_content': reasoning_content_chunk}
|
||||
get_token_usage(chunk, token_usage)
|
||||
|
||||
msg.append(AIMessage(full_filter_text))
|
||||
# self.record = save_full_analysis_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
# token_usage=token_usage,
|
||||
# answer=orjson.dumps({'content': full_analysis_text,
|
||||
# 'reasoning_content': full_thinking_text}).decode(),
|
||||
# full_message=orjson.dumps(history_msg +
|
||||
# [{'type': msg.type,
|
||||
# 'content': msg.content} for msg
|
||||
# in
|
||||
# analysis_msg]).decode())
|
||||
permission_sql_msg.append(AIMessage(full_filter_text))
|
||||
|
||||
self.current_logs[OperationEnum.GENERATE_SQL_WITH_PERMISSIONS] = end_log(session=self.session,
|
||||
log=self.current_logs[
|
||||
OperationEnum.GENERATE_SQL_WITH_PERMISSIONS],
|
||||
full_message=[
|
||||
{'type': msg.type,
|
||||
'content': msg.content}
|
||||
for msg in permission_sql_msg],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
|
||||
SQLBotLogUtil.info(full_filter_text)
|
||||
return full_filter_text
|
||||
|
||||
@@ -616,10 +662,16 @@ class LLMService:
|
||||
def generate_chart(self):
|
||||
# append current question
|
||||
self.chart_message.append(HumanMessage(self.chat_question.chart_user_question()))
|
||||
self.record = save_full_chart_message(session=self.session, record_id=self.record.id,
|
||||
full_message=orjson.dumps(
|
||||
[{'type': msg.type, 'content': msg.content} for msg in
|
||||
self.chart_message]).decode())
|
||||
|
||||
self.current_logs[OperationEnum.GENERATE_CHART] = start_log(session=self.session,
|
||||
ai_modal_id=self.chat_question.ai_modal_id,
|
||||
ai_modal_name=self.chat_question.ai_modal_name,
|
||||
operate=OperationEnum.GENERATE_CHART,
|
||||
record_id=self.record.id,
|
||||
full_message=[
|
||||
{'type': msg.type, 'content': msg.content} for
|
||||
msg
|
||||
in self.chart_message])
|
||||
full_thinking_text = ''
|
||||
full_chart_text = ''
|
||||
token_usage = {}
|
||||
@@ -640,13 +692,16 @@ class LLMService:
|
||||
get_token_usage(chunk, token_usage)
|
||||
|
||||
self.chart_message.append(AIMessage(full_chart_text))
|
||||
self.record = save_full_chart_message_and_answer(session=self.session, record_id=self.record.id,
|
||||
token_usage=token_usage,
|
||||
answer=orjson.dumps({'content': full_chart_text,
|
||||
'reasoning_content': full_thinking_text}).decode(),
|
||||
full_message=orjson.dumps(
|
||||
[{'type': msg.type, 'content': msg.content} for msg in
|
||||
self.chart_message]).decode())
|
||||
|
||||
self.record = save_chart_answer(session=self.session, record_id=self.record.id,
|
||||
answer=orjson.dumps({'content': full_chart_text}).decode())
|
||||
self.current_logs[OperationEnum.GENERATE_CHART] = end_log(session=self.session,
|
||||
log=self.current_logs[OperationEnum.GENERATE_CHART],
|
||||
full_message=[
|
||||
{'type': msg.type, 'content': msg.content}
|
||||
for msg in self.chart_message],
|
||||
reasoning_content=full_thinking_text,
|
||||
token_usage=token_usage)
|
||||
|
||||
def check_sql(self, res: str) -> tuple[any]:
|
||||
json_str = extract_nested_json(res)
|
||||
@@ -829,8 +884,8 @@ class LLMService:
|
||||
'type': 'datasource-result'}).decode() + '\n\n'
|
||||
if in_chat:
|
||||
yield 'data:' + orjson.dumps({'id': self.ds.id, 'datasource_name': self.ds.name,
|
||||
'engine_type': self.ds.type_name or self.ds.type,
|
||||
'type': 'datasource'}).decode() + '\n\n'
|
||||
'engine_type': self.ds.type_name or self.ds.type,
|
||||
'type': 'datasource'}).decode() + '\n\n'
|
||||
|
||||
self.chat_question.db_schema = self.out_ds_instance.get_db_schema(
|
||||
self.ds.id) if self.out_ds_instance else get_table_schema(session=self.session,
|
||||
@@ -909,7 +964,8 @@ class LLMService:
|
||||
chart = self.check_save_chart(res=full_chart_text)
|
||||
SQLBotLogUtil.info(chart)
|
||||
if in_chat:
|
||||
yield 'data:' + orjson.dumps({'content': orjson.dumps(chart).decode(), 'type': 'chart'}).decode() + '\n\n'
|
||||
yield 'data:' + orjson.dumps(
|
||||
{'content': orjson.dumps(chart).decode(), 'type': 'chart'}).decode() + '\n\n'
|
||||
else:
|
||||
data = []
|
||||
_fields = {}
|
||||
@@ -973,10 +1029,10 @@ class LLMService:
|
||||
|
||||
for chunk in res:
|
||||
if chunk.get('recommended_question'):
|
||||
yield orjson.dumps(
|
||||
yield 'data:' + orjson.dumps(
|
||||
{'content': chunk.get('recommended_question'), 'type': 'recommended_question'}).decode() + '\n\n'
|
||||
else:
|
||||
yield orjson.dumps(
|
||||
yield 'data:' + orjson.dumps(
|
||||
{'content': chunk.get('content'), 'reasoning_content': chunk.get('reasoning_content'),
|
||||
'type': 'recommended_question_result'}).decode() + '\n\n'
|
||||
|
||||
|
||||
@@ -104,6 +104,11 @@ async def ui(session: SessionDep, data: str = Form(), files: List[UploadFile] =
|
||||
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")
|
||||
async def clear_ui_cache(id: int):
|
||||
pass
|
||||
|
||||
@router.get("", response_model=list[AssistantModel])
|
||||
async def query(session: SessionDep):
|
||||
@@ -112,7 +117,7 @@ async def query(session: SessionDep):
|
||||
|
||||
@router.post("")
|
||||
async def add(request: Request, session: SessionDep, creator: AssistantBase):
|
||||
save(request, session, creator)
|
||||
await save(request, session, creator)
|
||||
|
||||
|
||||
@router.put("")
|
||||
|
||||
@@ -14,6 +14,8 @@ class Paginator:
|
||||
result_dict = {}
|
||||
if isinstance(row, int):
|
||||
return {'id': row}
|
||||
if isinstance(row, SQLModel) and not hasattr(row, '_fields'):
|
||||
return row.model_dump()
|
||||
for item, key in zip(row, row._fields):
|
||||
if isinstance(item, SQLModel):
|
||||
result_dict.update(item.model_dump())
|
||||
|
||||
+11
-11
@@ -91,20 +91,20 @@ exclude = ["alembic"]
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
"UP", # pyupgrade
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
"UP", # pyupgrade
|
||||
"ARG001", # unused arguments in functions
|
||||
]
|
||||
ignore = [
|
||||
"E501", # line too long, handled by black
|
||||
"B008", # do not perform function calls in argument defaults
|
||||
"W191", # indentation contains tabs
|
||||
"B904", # Allow raising exceptions without from e, for HTTPException
|
||||
"E501", # line too long, handled by black
|
||||
"B008", # do not perform function calls in argument defaults
|
||||
"W191", # indentation contains tabs
|
||||
"B904", # Allow raising exceptions without from e, for HTTPException
|
||||
]
|
||||
|
||||
[tool.ruff.lint.pyupgrade]
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
header_font_color: 'rgb(100, 106, 115)',
|
||||
x_type: 'right',
|
||||
y_type: 'bottom',
|
||||
x_value: '-5',
|
||||
y_value: '33',
|
||||
x_val: '30',
|
||||
y_val: '30',
|
||||
float_icon_drag: false,
|
||||
}
|
||||
const script_id_prefix = 'sqlbot-assistant-float-script-'
|
||||
const guideHtml = `
|
||||
@@ -35,8 +36,8 @@
|
||||
|
||||
const chatButtonHtml = (data) => `
|
||||
<div class="sqlbot-assistant-chat-button">
|
||||
<img style="height:100%;width:100%;display:none;" src="${data.float_icon}">
|
||||
<svg style="display:none;margin-right: 20px;" data-v-39a51454="" xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="none">
|
||||
<img style="height:30px;width:30px;display:none;" src="${data.float_icon}">
|
||||
<svg style="display:none;" data-v-39a51454="" xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="none">
|
||||
<path fill="#149CC5" d="M28.333 13.669h-.231c.138.758.207 1.527.206 2.298.005.946-.107 1.89-.335 2.808h.65a1.05 1.05 0 0 0 1.05-1.05V15.01a1.343 1.343 0 0 0-1.34-1.341"></path>
|
||||
<path fill="#69CAA4" d="M1.692 15.967c0-.77.068-1.54.206-2.298h-.23a1.34 1.34 0 0 0-1.342 1.34v2.716a1.05 1.05 0 0 0 1.05 1.05h.651a11.4 11.4 0 0 1-.335-2.808"></path>
|
||||
<path fill="url(#a)" d="M15 3.795c-6.89 0-12.474 5.282-12.474 12.171 0 6.89 5.585 10.239 12.474 10.239s12.474-3.35 12.474-10.238c0-6.89-5.585-12.172-12.474-12.172m3.026 17.33h-6.052a6 6 0 0 1-2.484-.535c-.564-.256-2.208.282-2.663-.127-.551-.495.117-1.969-.221-2.636a6.014 6.014 0 0 1 5.368-8.73h6.052a6.014 6.014 0 0 1 0 12.029"></path>
|
||||
@@ -158,16 +159,16 @@
|
||||
}
|
||||
const drag = (e) => {
|
||||
if (['touchmove', 'touchstart'].includes(e.type)) {
|
||||
chat_button.style.top = e.touches[0].clientY - chat_button_img.naturalHeight / 2 + 'px'
|
||||
chat_button.style.left = e.touches[0].clientX - chat_button_img.naturalWidth / 2 + 'px'
|
||||
chat_button.style.top = e.touches[0].clientY - chat_button_img.clientHeight / 2 + 'px'
|
||||
chat_button.style.left = e.touches[0].clientX - chat_button_img.clientHeight / 2 + 'px'
|
||||
} else {
|
||||
chat_button.style.top = e.y - chat_button_img.naturalHeight / 2 + 'px'
|
||||
chat_button.style.left = e.x - chat_button_img.naturalWidth / 2 + 'px'
|
||||
chat_button.style.top = e.y - chat_button_img.clientHeight / 2 + 'px'
|
||||
chat_button.style.left = e.x - chat_button_img.clientHeight / 2 + 'px'
|
||||
}
|
||||
chat_button.style.width = chat_button_img.naturalWidth + 'px'
|
||||
chat_button.style.height = chat_button_img.naturalHeight + 'px'
|
||||
chat_button.style.width = chat_button_img.clientHeight + 'px'
|
||||
chat_button.style.height = chat_button_img.clientHeight + 'px'
|
||||
}
|
||||
if (data.is_draggable) {
|
||||
if (data.float_icon_drag) {
|
||||
chat_button.addEventListener('drag', drag)
|
||||
chat_button.addEventListener('dragover', (e) => {
|
||||
e.preventDefault()
|
||||
@@ -234,14 +235,14 @@
|
||||
height: 64px;
|
||||
box-shadow: 1px 1px 1px 9999px rgba(0,0,0,.6);
|
||||
position: absolute;
|
||||
${data.x_type}: ${data.x_value}px;
|
||||
${data.y_type}: ${data.y_value}px;
|
||||
${data.x_type}: ${data.x_val}px;
|
||||
${data.y_type}: ${data.y_val}px;
|
||||
z-index: 10001;
|
||||
}
|
||||
#sqlbot-assistant .sqlbot-assistant-tips {
|
||||
position: fixed;
|
||||
${data.x_type}:calc(${data.x_value}px + 75px);
|
||||
${data.y_type}: calc(${data.y_value}px + 0px);
|
||||
${data.x_type}:calc(${data.x_val}px + 75px);
|
||||
${data.y_type}: calc(${data.y_val}px + 0px);
|
||||
padding: 22px 24px 24px;
|
||||
border-radius: 6px;
|
||||
color: #ffffff;
|
||||
@@ -297,76 +298,76 @@
|
||||
display:none;
|
||||
}
|
||||
@media only screen and (max-width: 768px) {
|
||||
#sqlbot-assistant-chat-container {
|
||||
width: 100%;
|
||||
height: 70%;
|
||||
right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
#sqlbot-assistant .sqlbot-assistant-chat-button{
|
||||
position: fixed;
|
||||
${data.x_type}: ${data.x_value}px;
|
||||
${data.y_type}: ${data.y_value}px;
|
||||
cursor: pointer;
|
||||
z-index:10000;
|
||||
#sqlbot-assistant-chat-container {
|
||||
width: 100%;
|
||||
height: 70%;
|
||||
right: 0 !important;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container{
|
||||
z-index:10000;position: relative;
|
||||
border-radius: 8px;
|
||||
//border: 1px solid #ffffff;
|
||||
background: linear-gradient(188deg, rgba(235, 241, 255, 0.20) 39.6%, rgba(231, 249, 255, 0.20) 94.3%), #EFF0F1;
|
||||
box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.10);
|
||||
position: fixed;bottom: 16px;right: 16px;overflow: hidden;
|
||||
}
|
||||
|
||||
#sqlbot-assistant .sqlbot-assistant-chat-button{
|
||||
position: fixed;
|
||||
${data.x_type}: ${data.x_val}px;
|
||||
${data.y_type}: ${data.y_val}px;
|
||||
cursor: pointer;
|
||||
z-index:10000;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container{
|
||||
z-index:10000;position: relative;
|
||||
border-radius: 8px;
|
||||
//border: 1px solid #ffffff;
|
||||
background: linear-gradient(188deg, rgba(235, 241, 255, 0.20) 39.6%, rgba(231, 249, 255, 0.20) 94.3%), #EFF0F1;
|
||||
box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.10);
|
||||
position: fixed;bottom: 16px;right: 16px;overflow: hidden;
|
||||
}
|
||||
|
||||
.ed-overlay-dialog {
|
||||
margin-top: 50px;
|
||||
}
|
||||
.ed-drawer {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate{
|
||||
top: 18px;
|
||||
right: 15px;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 18px;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-chat-close{
|
||||
margin-left:15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-openviewport{
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-closeviewport{
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-viewportnone{
|
||||
display:none;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container #sqlbot-assistant-chat-iframe-${data.id} {
|
||||
height:100%;
|
||||
width:100%;
|
||||
border: none;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container {
|
||||
animation: appear .4s ease-in-out;
|
||||
}
|
||||
@keyframes appear {
|
||||
from {
|
||||
height: 0;;
|
||||
}
|
||||
|
||||
.ed-overlay-dialog {
|
||||
margin-top: 50px;
|
||||
}
|
||||
.ed-drawer {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate{
|
||||
top: 18px;
|
||||
right: 15px;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 18px;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-chat-close{
|
||||
margin-left:15px;
|
||||
cursor: pointer;
|
||||
to {
|
||||
height: 600px;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-openviewport{
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-closeviewport{
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-viewportnone{
|
||||
display:none;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container #sqlbot-assistant-chat-iframe-${data.id}{
|
||||
height:100%;
|
||||
width:100%;
|
||||
border: none;
|
||||
}
|
||||
#sqlbot-assistant #sqlbot-assistant-chat-container {
|
||||
animation: appear .4s ease-in-out;
|
||||
}
|
||||
@keyframes appear {
|
||||
from {
|
||||
height: 0;;
|
||||
}
|
||||
|
||||
to {
|
||||
height: 600px;
|
||||
}
|
||||
}`.replaceAll('#sqlbot-assistant ', `#${sqlbot_assistantId} `)
|
||||
}`.replaceAll('#sqlbot-assistant ', `#${sqlbot_assistantId} `)
|
||||
root.appendChild(style)
|
||||
}
|
||||
function getParam(src, key) {
|
||||
@@ -460,7 +461,10 @@
|
||||
}
|
||||
const data = res.data
|
||||
const config_json = data.configuration
|
||||
let tempData = Object.assign(defaultData, { id, domain_url, name: data.name })
|
||||
let tempData = Object.assign(defaultData, data)
|
||||
if (tempData.configuration) {
|
||||
delete tempData.configuration
|
||||
}
|
||||
if (config_json) {
|
||||
const config = JSON.parse(config_json)
|
||||
if (config) {
|
||||
@@ -468,6 +472,18 @@
|
||||
tempData = Object.assign(tempData, config)
|
||||
}
|
||||
}
|
||||
tempData['id'] = id
|
||||
tempData['domain_url'] = domain_url
|
||||
|
||||
if (tempData['float_icon'] && !tempData['float_icon'].startsWith('http://')) {
|
||||
tempData['float_icon'] =
|
||||
`${domain_url}/api/v1/system/assistant/picture/${tempData['float_icon']}`
|
||||
|
||||
if (domain_url.includes('5173')) {
|
||||
tempData['float_icon'] = tempData['float_icon'].replace('5173', '8000')
|
||||
}
|
||||
}
|
||||
|
||||
tempData['online'] = online && online.toString().toLowerCase() == 'true'
|
||||
initsqlbot_assistant(tempData)
|
||||
if (data.type == 1) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.75 14.25V15.75H2.25V14.25H15.75ZM15.75 3.75H2.25V15.75L2.09692 15.7419C1.39076 15.6704 0.82965 15.1092 0.758057 14.4031L0.75 14.25V3.75C0.75 2.92157 1.42157 2.25 2.25 2.25H15.75C16.5784 2.25 17.25 2.92157 17.25 3.75V14.25C17.25 15.0784 16.5784 15.75 15.75 15.75V3.75Z" fill=""/>
|
||||
<path d="M5.625 5.25H3.375C3.27554 5.25 3.18016 5.28951 3.10983 5.35984C3.03951 5.43016 3 5.52554 3 5.625V6.375C3 6.47446 3.03951 6.56984 3.10983 6.64017C3.18016 6.71049 3.27554 6.75 3.375 6.75H5.625C5.67425 6.75 5.72301 6.7403 5.76851 6.72145C5.814 6.70261 5.85534 6.67499 5.89017 6.64017C5.92499 6.60534 5.95261 6.564 5.97146 6.51851C5.9903 6.47301 6 6.42425 6 6.375V5.625C6 5.57575 5.9903 5.52699 5.97146 5.48149C5.95261 5.436 5.92499 5.39466 5.89017 5.35984C5.85534 5.32501 5.814 5.29739 5.76851 5.27855C5.72301 5.2597 5.67425 5.25 5.625 5.25Z" fill=""/>
|
||||
<path d="M5.625 7.5H3.375C3.27554 7.5 3.18016 7.53951 3.10983 7.60984C3.03951 7.68016 3 7.77554 3 7.875V8.625C3 8.72446 3.03951 8.81984 3.10983 8.89017C3.18016 8.96049 3.27554 9 3.375 9H5.625C5.67425 9 5.72301 8.9903 5.76851 8.97145C5.814 8.95261 5.85534 8.92499 5.89017 8.89017C5.92499 8.85534 5.95261 8.814 5.97146 8.76851C5.9903 8.72301 6 8.67425 6 8.625V7.875C6 7.82575 5.9903 7.77699 5.97146 7.73149C5.95261 7.686 5.92499 7.64466 5.89017 7.60984C5.85534 7.57501 5.814 7.54739 5.76851 7.52855C5.72301 7.5097 5.67425 7.5 5.625 7.5Z" fill=""/>
|
||||
<path d="M6.75 3.75H8.25V14.25H6.75V3.75Z" fill=""/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,3 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.15199 11.5968C7.31471 11.4341 7.57853 11.4341 7.74125 11.5968L8.33051 12.1861C8.49323 12.3488 8.49323 12.6126 8.33051 12.7754L4.99606 16.1087H7.36641C7.59652 16.1087 7.78307 16.2952 7.78307 16.5254V17.3587C7.78307 17.5888 7.59652 17.7754 7.36641 17.7754H3.05575C2.82563 17.7754 2.61729 17.6821 2.46649 17.5313C2.31569 17.3805 2.22241 17.1721 2.22241 16.942V12.6422C2.22241 12.4121 2.40896 12.2255 2.63908 12.2255H3.47241C3.70253 12.2255 3.88908 12.4121 3.88908 12.6422V14.8586L7.15199 11.5968ZM16.9369 2.22224C17.167 2.22224 17.3753 2.31552 17.5261 2.46632C17.6769 2.61713 17.7702 2.82546 17.7702 3.05558V7.35539C17.7702 7.5855 17.5837 7.77205 17.3535 7.77205H16.5202C16.2901 7.77205 16.1035 7.5855 16.1035 7.35539V5.13895L12.8406 8.40076C12.6779 8.56347 12.4141 8.56347 12.2514 8.40076L11.6621 7.8115C11.4994 7.64878 11.4994 7.38496 11.6621 7.22224L14.9966 3.88891H12.6262C12.3961 3.88891 12.2095 3.70236 12.2095 3.47224V2.63891C12.2095 2.40879 12.3961 2.22224 12.6262 2.22224H16.9369Z" fill="#1F2329"/>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.15199 11.5968C7.31471 11.4341 7.57853 11.4341 7.74125 11.5968L8.33051 12.1861C8.49323 12.3488 8.49323 12.6126 8.33051 12.7754L4.99606 16.1087H7.36641C7.59652 16.1087 7.78307 16.2952 7.78307 16.5254V17.3587C7.78307 17.5888 7.59652 17.7754 7.36641 17.7754H3.05575C2.82563 17.7754 2.61729 17.6821 2.46649 17.5313C2.31569 17.3805 2.22241 17.1721 2.22241 16.942V12.6422C2.22241 12.4121 2.40896 12.2255 2.63908 12.2255H3.47241C3.70253 12.2255 3.88908 12.4121 3.88908 12.6422V14.8586L7.15199 11.5968ZM16.9369 2.22224C17.167 2.22224 17.3753 2.31552 17.5261 2.46632C17.6769 2.61713 17.7702 2.82546 17.7702 3.05558V7.35539C17.7702 7.5855 17.5837 7.77205 17.3535 7.77205H16.5202C16.2901 7.77205 16.1035 7.5855 16.1035 7.35539V5.13895L12.8406 8.40076C12.6779 8.56347 12.4141 8.56347 12.2514 8.40076L11.6621 7.8115C11.4994 7.64878 11.4994 7.38496 11.6621 7.22224L14.9966 3.88891H12.6262C12.3961 3.88891 12.2095 3.70236 12.2095 3.47224V2.63891C12.2095 2.40879 12.3961 2.22224 12.6262 2.22224H16.9369Z" fill=""/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,6 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.75 14.25V15.75H2.25V14.25H15.75ZM15.75 3.75H2.25V15.75L2.09692 15.7419C1.39076 15.6704 0.82965 15.1092 0.758057 14.4031L0.75 14.25V3.75C0.75 2.92157 1.42157 2.25 2.25 2.25H15.75C16.5784 2.25 17.25 2.92157 17.25 3.75V14.25C17.25 15.0784 16.5784 15.75 15.75 15.75V3.75Z" fill=""/>
|
||||
<path d="M5.625 5.25H3.375C3.27554 5.25 3.18016 5.28951 3.10983 5.35984C3.03951 5.43016 3 5.52554 3 5.625V6.375C3 6.47446 3.03951 6.56984 3.10983 6.64017C3.18016 6.71049 3.27554 6.75 3.375 6.75H5.625C5.67425 6.75 5.72301 6.7403 5.76851 6.72145C5.814 6.70261 5.85534 6.67499 5.89017 6.64017C5.92499 6.60534 5.95261 6.564 5.97146 6.51851C5.9903 6.47301 6 6.42425 6 6.375V5.625C6 5.57575 5.9903 5.52699 5.97146 5.48149C5.95261 5.436 5.92499 5.39466 5.89017 5.35984C5.85534 5.32501 5.814 5.29739 5.76851 5.27855C5.72301 5.2597 5.67425 5.25 5.625 5.25Z" fill=""/>
|
||||
<path d="M5.625 7.5H3.375C3.27554 7.5 3.18016 7.53951 3.10983 7.60984C3.03951 7.68016 3 7.77554 3 7.875V8.625C3 8.72446 3.03951 8.81984 3.10983 8.89017C3.18016 8.96049 3.27554 9 3.375 9H5.625C5.67425 9 5.72301 8.9903 5.76851 8.97145C5.814 8.95261 5.85534 8.92499 5.89017 8.89017C5.92499 8.85534 5.95261 8.814 5.97146 8.76851C5.9903 8.72301 6 8.67425 6 8.625V7.875C6 7.82575 5.9903 7.77699 5.97146 7.73149C5.95261 7.686 5.92499 7.64466 5.89017 7.60984C5.85534 7.57501 5.814 7.54739 5.76851 7.52855C5.72301 7.5097 5.67425 7.5 5.625 7.5Z" fill=""/>
|
||||
<path d="M6.75 3.75H8.25V14.25H6.75V3.75Z" fill=""/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -63,7 +63,9 @@ async function getRecommendQuestions() {
|
||||
const controller: AbortController = new AbortController()
|
||||
const response = await chatApi.recommendQuestions(props.recordId, controller)
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
const decoder = new TextDecoder('utf-8')
|
||||
|
||||
let tempResult = ''
|
||||
|
||||
while (true) {
|
||||
if (stopFlag.value) {
|
||||
@@ -77,60 +79,56 @@ async function getRecommendQuestions() {
|
||||
break
|
||||
}
|
||||
|
||||
const chunk = decoder.decode(value)
|
||||
|
||||
let _list = [chunk]
|
||||
|
||||
const lines = chunk.trim().split('}\n\n{')
|
||||
if (lines.length > 1) {
|
||||
_list = []
|
||||
for (let line of lines) {
|
||||
if (!line.trim().startsWith('{')) {
|
||||
line = '{' + line.trim()
|
||||
}
|
||||
if (!line.trim().endsWith('}')) {
|
||||
line = line.trim() + '}'
|
||||
}
|
||||
_list.push(line)
|
||||
}
|
||||
let chunk = decoder.decode(value, { stream: true })
|
||||
tempResult += chunk
|
||||
const split = tempResult.match(/data:.*}\n\n/g)
|
||||
if (split) {
|
||||
chunk = split.join('')
|
||||
tempResult = tempResult.replace(chunk, '')
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
for (const str of _list) {
|
||||
let data
|
||||
try {
|
||||
data = JSON.parse(str)
|
||||
} catch (err) {
|
||||
console.error('JSON string:', str)
|
||||
throw err
|
||||
}
|
||||
if (chunk && chunk.startsWith('data:{')) {
|
||||
if (split) {
|
||||
for (const str of split) {
|
||||
let data
|
||||
try {
|
||||
data = JSON.parse(str.replace('data:{', '{'))
|
||||
} catch (err) {
|
||||
console.error('JSON string:', str)
|
||||
throw err
|
||||
}
|
||||
|
||||
if (data.code && data.code !== 200) {
|
||||
ElMessage({
|
||||
message: data.msg,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (data.code && data.code !== 200) {
|
||||
ElMessage({
|
||||
message: data.msg,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case 'recommended_question':
|
||||
if (
|
||||
data.content &&
|
||||
data.content.length > 0 &&
|
||||
startsWith(data.content.trim(), '[') &&
|
||||
endsWith(data.content.trim(), ']')
|
||||
) {
|
||||
if (_currentChat.value?.records) {
|
||||
for (let record of _currentChat.value.records) {
|
||||
if (record.id === props.recordId) {
|
||||
record.recommended_question = data.content
|
||||
switch (data.type) {
|
||||
case 'recommended_question':
|
||||
if (
|
||||
data.content &&
|
||||
data.content.length > 0 &&
|
||||
startsWith(data.content.trim(), '[') &&
|
||||
endsWith(data.content.trim(), ']')
|
||||
) {
|
||||
if (_currentChat.value?.records) {
|
||||
for (let record of _currentChat.value.records) {
|
||||
if (record.id === props.recordId) {
|
||||
record.recommended_question = data.content
|
||||
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,17 @@
|
||||
</template>
|
||||
|
||||
<div v-else class="assistant-desc">
|
||||
<img :src="logoAssistant" class="logo" width="30px" height="30px" alt="" />
|
||||
<img
|
||||
v-if="logoAssistant"
|
||||
:src="logoAssistant"
|
||||
class="logo"
|
||||
width="30px"
|
||||
height="30px"
|
||||
alt=""
|
||||
/>
|
||||
<el-icon v-else size="32">
|
||||
<logo_fold />
|
||||
</el-icon>
|
||||
<div class="i-am">{{ welcome }}</div>
|
||||
<div class="i-can">{{ welcomeDesc }}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import icon_sidebar_outlined from '@/assets/embedded/icon_sidebar_outlined.svg'
|
||||
import icon_new_chat_outlined from '@/assets/embedded/icon_new-chat_outlined.svg'
|
||||
import icon_sidebar_outlined from '@/assets/embedded/icon_sidebar_outlined_nofill.svg'
|
||||
import icon_new_chat_outlined from '@/assets/svg/icon_new_chat_outlined.svg'
|
||||
import LOGO from '@/assets/embedded/LOGO.png'
|
||||
import disable_answer from '@/assets/embedded/disable.png'
|
||||
import icon_close_outlined from '@/assets/svg/icon_close_outlined.svg'
|
||||
@@ -99,6 +99,7 @@ const pageLogo = computed(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
color: var(--ed-text-color-primary);
|
||||
.logo {
|
||||
margin: 0 8px 0 16px;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="sqlbot-assistant-container">
|
||||
<div class="header">
|
||||
<div class="header" :style="{ color: customSet.header_font_color }">
|
||||
<el-icon size="20" @click="openHistory">
|
||||
<icon_sidebar_outlined></icon_sidebar_outlined>
|
||||
</el-icon>
|
||||
@@ -30,13 +30,14 @@ import { onBeforeMount, nextTick, onBeforeUnmount, ref, onMounted, reactive } fr
|
||||
import ChatComponent from '@/views/chat/index.vue'
|
||||
import { request } from '@/utils/request'
|
||||
import LOGO from '@/assets/embedded/LOGO.png'
|
||||
import icon_sidebar_outlined from '@/assets/embedded/icon_sidebar_outlined.svg'
|
||||
import icon_sidebar_outlined from '@/assets/embedded/icon_sidebar_outlined_nofill.svg'
|
||||
import icon_new_chat_outlined from '@/assets/svg/icon_new_chat_outlined.svg'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { assistantApi } from '@/api/assistant'
|
||||
import { useAssistantStore } from '@/stores/assistant'
|
||||
import { setCurrentColor } from '@/utils/utils'
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
const assistantStore = useAssistantStore()
|
||||
const route = useRoute()
|
||||
const chatRef = ref()
|
||||
@@ -101,8 +102,8 @@ onMounted(() => {
|
||||
})
|
||||
const customSet = reactive({
|
||||
name: '',
|
||||
welcome: '',
|
||||
welcome_desc: '',
|
||||
welcome: t('embedded.i_am_sqlbot'),
|
||||
welcome_desc: t('embedded.data_analysis_now'),
|
||||
theme: '#1CBA90',
|
||||
header_font_color: '#1F2329',
|
||||
}) as { [key: string]: any }
|
||||
@@ -124,23 +125,7 @@ onBeforeMount(async () => {
|
||||
ElMessage.error('Miss assistant id, please check assistant url')
|
||||
return
|
||||
}
|
||||
request.get(`/system/assistant/info/${assistantId}`).then((res) => {
|
||||
if (res?.configuration) {
|
||||
const rawData = JSON.parse(res?.configuration)
|
||||
logo.value = baseUrl + rawData.logo
|
||||
|
||||
for (const key in customSet) {
|
||||
if (Object.prototype.hasOwnProperty.call(customSet, key) && rawData[key]) {
|
||||
customSet[key] = rawData[key]
|
||||
}
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
setPageCustomColor(customSet.theme)
|
||||
setPageHeaderFontColor(customSet.header_font_color)
|
||||
})
|
||||
}
|
||||
})
|
||||
const online = route.query.online
|
||||
setFormatOnline(online)
|
||||
|
||||
@@ -165,6 +150,26 @@ onBeforeMount(async () => {
|
||||
messageId: assistantId,
|
||||
}
|
||||
window.parent.postMessage(readyData, '*')
|
||||
|
||||
request.get(`/system/assistant/${assistantId}`).then((res) => {
|
||||
if (res?.configuration) {
|
||||
const rawData = JSON.parse(res?.configuration)
|
||||
if (rawData.logo) {
|
||||
logo.value = baseUrl + rawData.logo
|
||||
}
|
||||
|
||||
for (const key in customSet) {
|
||||
if (Object.prototype.hasOwnProperty.call(customSet, key) && rawData[key]) {
|
||||
customSet[key] = rawData[key]
|
||||
}
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
setPageCustomColor(customSet.theme)
|
||||
setPageHeaderFontColor(customSet.header_font_color)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
||||
@@ -66,8 +66,8 @@ const defaultSqlBotForm = reactive<SqlBotForm>({
|
||||
name: t('embedded.intelligent_customer_service'),
|
||||
x_type: 'right',
|
||||
y_type: 'bottom',
|
||||
x_val: 0,
|
||||
y_val: 33,
|
||||
x_val: 30,
|
||||
y_val: 30,
|
||||
float_icon_drag: false,
|
||||
welcome: t('embedded.i_am_sqlbot'),
|
||||
welcome_desc: t('embedded.data_analysis_now'),
|
||||
|
||||
Reference in New Issue
Block a user