更新python后端
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
from config.milvus import knVectorstore,memVectorstore
|
||||
from langchain.schema import Document
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
from typing import List, Dict, Any
|
||||
|
||||
def get_knowledge_by_key_words(key_words: str, kn_ids: List[str]) -> str:
|
||||
"""
|
||||
根据关键词和 kn_ids 列表,在知识库中检索相关内容,并返回整理后的文本字符串
|
||||
"""
|
||||
# 构建过滤表达式:只查 kn_ids 范围内的
|
||||
if kn_ids:
|
||||
ids_expr = " or ".join([f'kn_id == "{kid}"' for kid in kn_ids])
|
||||
expr = f"({ids_expr})"
|
||||
else:
|
||||
return "未找到相关的知识。"
|
||||
|
||||
result = knVectorstore.similarity_search(
|
||||
query=key_words,
|
||||
k=3, # 可调节返回条数
|
||||
expr=expr
|
||||
)
|
||||
|
||||
# 整理成字符串
|
||||
doc_texts = []
|
||||
for idx, doc in enumerate(result, start=1):
|
||||
text = doc.page_content.strip()
|
||||
if text:
|
||||
# 可以加个编号,便于LLM区分
|
||||
doc_texts.append(f"[文档{idx}]: {text}")
|
||||
|
||||
# 拼成一个大字符串,用换行隔开
|
||||
combined_text = "\n\n".join(doc_texts)
|
||||
return combined_text
|
||||
|
||||
|
||||
def get_memory_by_key_words(key_words: str, ai_ids: List[str]) -> str:
|
||||
print("ai_id是:" , ai_ids)
|
||||
"""
|
||||
根据关键词和 ai_ids 列表,在知识库中检索相关内容,并返回整理后的文本字符串
|
||||
"""
|
||||
# 构建过滤表达式:只查 kn_ids 范围内的
|
||||
if ai_ids:
|
||||
ids_expr = " or ".join([f'ai_id == "{kid}"' for kid in ai_ids])
|
||||
expr = f"({ids_expr})"
|
||||
else:
|
||||
expr = "" # 不限制 kn_id todo 实际上应该不反悔任何内容
|
||||
|
||||
result = memVectorstore.similarity_search(
|
||||
query=key_words,
|
||||
k=5, # 可调节返回条数
|
||||
expr=expr
|
||||
)
|
||||
|
||||
# 整理成字符串
|
||||
doc_texts = []
|
||||
for idx, doc in enumerate(result, start=1):
|
||||
text = doc.page_content.strip()
|
||||
if text:
|
||||
# 可以加个编号,便于LLM区分
|
||||
doc_texts.append(f"[记忆{idx}]: {text}")
|
||||
|
||||
# 拼成一个大字符串,用换行隔开
|
||||
combined_text = "\n\n".join(doc_texts)
|
||||
return combined_text
|
||||
def get_knowledge_by_base_id(base_id: str):
|
||||
expr = f'kn_id == "{base_id}"' # base_id 会被替换
|
||||
result = knVectorstore.similarity_search(
|
||||
query="", # 如果只想用过滤条件,可以传空字符串
|
||||
k=100,
|
||||
expr=expr
|
||||
)
|
||||
return [
|
||||
{
|
||||
"id": str(doc.metadata["id"]),
|
||||
"text": doc.page_content,
|
||||
"is_active": doc.metadata["is_active"],
|
||||
}
|
||||
for doc in result
|
||||
]
|
||||
|
||||
def add_knowledge(text: str, is_active: bool, base_id: str, user_id: str):
|
||||
docs = [
|
||||
Document(
|
||||
page_content=text,
|
||||
metadata={
|
||||
"kn_id": str(base_id),
|
||||
"created_by": str(user_id),
|
||||
"created_at": datetime.now().isoformat(),
|
||||
"is_active": is_active,
|
||||
}
|
||||
)
|
||||
]
|
||||
return knVectorstore.add_documents(docs)
|
||||
|
||||
def add_memory(ai_id:str,mem: str, user_id: str,is_active: bool):
|
||||
docs = [
|
||||
Document(
|
||||
page_content=mem,
|
||||
metadata={
|
||||
"ai_id": str(ai_id),
|
||||
"created_by": str(user_id),
|
||||
"created_at": datetime.now().isoformat(),
|
||||
"is_active": is_active,
|
||||
}
|
||||
)
|
||||
]
|
||||
return memVectorstore.add_documents(docs)
|
||||
+324
-30
@@ -1,11 +1,16 @@
|
||||
import psycopg
|
||||
from langchain_postgres import PostgresChatMessageHistory
|
||||
from config.pgDb import database_name,getConn
|
||||
from config.pgDb import pg_pool
|
||||
from config.ssDb import mssql_pool
|
||||
from typing import List, Dict
|
||||
import json
|
||||
|
||||
# ————————————————————————————————————————————————————AI角色———————————————————————————————
|
||||
|
||||
database_name = "ai_chat_history"
|
||||
|
||||
|
||||
def get_ai_personality(ai_id: str):
|
||||
with getConn() as conn:
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT ai_personality FROM ai_chat_profiles WHERE id = %s",
|
||||
@@ -16,9 +21,33 @@ def get_ai_personality(ai_id: str):
|
||||
return row[0]
|
||||
else:
|
||||
return "你是一个乐于助人的AI助手,请保持中文简洁回答用户。"
|
||||
|
||||
def get_all_ai(user_id: str) -> List[Dict]:
|
||||
with getConn() as conn:
|
||||
|
||||
|
||||
def get_description(ai_id: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT description FROM ai_chat_profiles WHERE id = %s",
|
||||
(ai_id,)
|
||||
)
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
return row[0]
|
||||
else:
|
||||
return "你是一个乐于助人的AI助手,请保持中文简洁回答用户。"
|
||||
|
||||
|
||||
def get_ai_available_kn_bases(ai_id: str) -> List[str]:
|
||||
with pg_pool.getConn() as conn:
|
||||
result = conn.execute(
|
||||
"SELECT available_kn_bases FROM ai_chat_profiles WHERE id = %s",
|
||||
(ai_id,)
|
||||
)
|
||||
return result.fetchone()[0]
|
||||
|
||||
|
||||
def get_all_ai_bot(user_id: str, module: str) -> List[Dict]:
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
# 查询用户角色
|
||||
cur.execute(
|
||||
@@ -31,27 +60,43 @@ def get_all_ai(user_id: str) -> List[Dict]:
|
||||
user_roles = role_row[0]
|
||||
|
||||
# 查询 AI 角色 JSON 字段包含用户角色
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT id, name, welcome_words
|
||||
SELECT id, title, description, welcome_words, ai_personality, available_report_tables, available_kn_bases
|
||||
FROM ai_chat_profiles
|
||||
WHERE availabel_roles::jsonb ?| %s
|
||||
WHERE available_module = %s
|
||||
AND is_active = TRUE
|
||||
AND available_roles::jsonb ?| %s
|
||||
""",
|
||||
(user_roles,) # user_roles 是 list,比如 ["a", "b", "c"]
|
||||
(module, user_roles)
|
||||
)
|
||||
rows = cur.fetchall()
|
||||
return [
|
||||
{
|
||||
"id": row[0],
|
||||
"name": row[1],
|
||||
"welcomeWords": row[2],
|
||||
}
|
||||
for row in rows
|
||||
]
|
||||
result = []
|
||||
for row in rows:
|
||||
# row 索引对应 SELECT 字段顺序
|
||||
id_, title, description, welcome_words, ai_personality, available_report_tables, available_kn_bases = row
|
||||
|
||||
# 解析 JSON
|
||||
roles_json = ai_personality if ai_personality else {}
|
||||
result.append({
|
||||
"id": id_,
|
||||
"title": title,
|
||||
"description": description,
|
||||
"welcome_words": welcome_words,
|
||||
"name": roles_json.get("名字", ""),
|
||||
"role": roles_json.get("性格", ""),
|
||||
"service": roles_json.get("业务", ""),
|
||||
"available_report_tables": available_report_tables,
|
||||
"available_kn_bases": available_kn_bases
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# ————————————————————————————————————————————————————消息———————————————————————————————
|
||||
def insert_message(session_id: str, isAI: bool, content: str):
|
||||
with getConn() as conn:
|
||||
with pg_pool.getConn() as conn:
|
||||
history = PostgresChatMessageHistory(
|
||||
database_name,
|
||||
session_id,
|
||||
@@ -62,34 +107,56 @@ def insert_message(session_id: str, isAI: bool, content: str):
|
||||
else:
|
||||
history.add_user_message(content)
|
||||
|
||||
|
||||
def get_history(session_id: str):
|
||||
with getConn() as conn:
|
||||
simplified = []
|
||||
with pg_pool.getConn() as conn:
|
||||
history = PostgresChatMessageHistory(
|
||||
database_name,
|
||||
session_id,
|
||||
sync_connection=conn
|
||||
)
|
||||
simplified = []
|
||||
for msg in history.messages:
|
||||
simplified.append({
|
||||
"type": msg.type,
|
||||
"content": msg.content
|
||||
})
|
||||
return simplified
|
||||
|
||||
|
||||
def get_history_with_time(session_id: str, number: int):
|
||||
simplified = []
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
f"SELECT message, created_at FROM ai_chat_history WHERE session_id = '{session_id}' ORDER BY created_at DESC LIMIT {number}")
|
||||
rows = cur.fetchall()
|
||||
simplified = []
|
||||
|
||||
for row in rows:
|
||||
msg_dict = row[0]
|
||||
simplified.append({
|
||||
"type": msg_dict.get("type"),
|
||||
"created_at": row[1].isoformat(),
|
||||
"content": msg_dict.get("data", {}).get("content")
|
||||
})
|
||||
|
||||
return simplified
|
||||
|
||||
|
||||
# ————————————————————————————————————————————————————会话———————————————————————————————
|
||||
def insert_session(user_id: str,ai_id:str, session_id: str,session_title: str):
|
||||
with getConn() as coon:
|
||||
def insert_session(user_id: str, ai_id: str, session_id: str, session_title: str, available_module):
|
||||
with pg_pool.getConn() as coon:
|
||||
with coon.cursor() as cur:
|
||||
cur.execute(
|
||||
"INSERT INTO ai_chat_sessions (id ,user_id, ai_id, title, created_at, updated_at) VALUES (%s, %s, %s, %s, NOW(), NOW())",
|
||||
(session_id, user_id, ai_id, session_title )
|
||||
"INSERT INTO ai_chat_sessions (id ,user_id, ai_id, title, available_module, created_at, updated_at) VALUES (%s, %s, %s, %s,%s, NOW(), NOW())",
|
||||
(session_id, user_id, ai_id, session_title, available_module)
|
||||
)
|
||||
coon.commit()
|
||||
|
||||
|
||||
def update_session_updated_at(session_id: str):
|
||||
with getConn() as conn:
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE ai_chat_sessions SET updated_at = NOW() WHERE id = %s",
|
||||
@@ -97,13 +164,18 @@ def update_session_updated_at(session_id: str):
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
def get_sessions(user_id: str):
|
||||
with getConn() as conn:
|
||||
|
||||
def get_sessions(user_id: str, available_module: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT id, title, updated_at FROM ai_chat_sessions WHERE user_id = %s ORDER BY updated_at DESC",
|
||||
(user_id,)
|
||||
"SELECT id, title, updated_at "
|
||||
"FROM ai_chat_sessions "
|
||||
"WHERE user_id = %s AND available_module = %s "
|
||||
"ORDER BY updated_at DESC",
|
||||
(user_id, available_module)
|
||||
)
|
||||
|
||||
sessions = cur.fetchall()
|
||||
return [
|
||||
{
|
||||
@@ -112,4 +184,226 @@ def get_sessions(user_id: str):
|
||||
"updated_at": row[2]
|
||||
}
|
||||
for row in sessions
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
# ————————————————————————————————————————————————————报表———————————————————————————————
|
||||
def get_reports(user_id: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT id, title FROM ai_reports WHERE created_by = %s AND is_masked = TRUE ORDER BY created_at DESC",
|
||||
(user_id,)
|
||||
)
|
||||
reports = cur.fetchall()
|
||||
return [
|
||||
{
|
||||
"id": row[0],
|
||||
"title": row[1]
|
||||
}
|
||||
for row in reports
|
||||
]
|
||||
|
||||
|
||||
def save_report(id: str, user_id: str, title: str, sql: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"INSERT INTO ai_reports (id, title, sql, created_at, created_by , is_masked) VALUES (%s, %s, %s, NOW(), %s, FALSE) RETURNING id",
|
||||
(id, title, sql, user_id)
|
||||
)
|
||||
report_id = cur.fetchone()[0]
|
||||
conn.commit()
|
||||
return report_id
|
||||
|
||||
|
||||
def maked_report(report_id: str, title: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE ai_reports SET title = %s, is_masked = TRUE WHERE id = %s",
|
||||
(title, report_id)
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
|
||||
def getSQL(reportId: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT sql FROM ai_reports WHERE id = %s",
|
||||
(reportId,)
|
||||
)
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
return row[0]
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
def get_available_tables_str(aiId: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
# 1. 先取 AI 可用的数据库表
|
||||
cur.execute(
|
||||
"SELECT available_report_tables FROM ai_chat_profiles WHERE id = %s",
|
||||
(aiId,)
|
||||
)
|
||||
role_row = cur.fetchone()
|
||||
if not role_row:
|
||||
return "无数据库表可用"
|
||||
available_tables = role_row[0] # 假设是列表
|
||||
|
||||
if not available_tables:
|
||||
return "无数据库表可用"
|
||||
|
||||
# 2. 构造 IN 查询占位符
|
||||
placeholders = ','.join(['%s'] * len(available_tables))
|
||||
sql_query = f"""
|
||||
SELECT id, name, description
|
||||
FROM ai_reports_tables
|
||||
WHERE id IN ({placeholders}) AND is_active = TRUE
|
||||
"""
|
||||
cur.execute(sql_query, available_tables)
|
||||
tableIds = cur.fetchall()
|
||||
|
||||
# 3. 查询这些表的字段
|
||||
result = ""
|
||||
for table in tableIds:
|
||||
cur.execute(
|
||||
"SELECT name, type, description FROM ai_reports_fields WHERE table_id = %s AND is_active = TRUE",
|
||||
(table[0],)
|
||||
)
|
||||
columns = cur.fetchall()
|
||||
result += f"{table[1]}:{table[2]}\n"
|
||||
result += "字段名,数据类型,描述\n"
|
||||
for column in columns:
|
||||
result += f"{column[0]},{column[1]}, {column[2]}\n"
|
||||
result += "\n"
|
||||
return result
|
||||
|
||||
|
||||
# -------------------报表数据源------------------
|
||||
# 获取表
|
||||
def get_available_tables():
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"SELECT id, name, description,is_active FROM ai_reports_tables",
|
||||
)
|
||||
return [{"id": row[0], "name": row[1], "description": row[2], "is_active": row[3]} for row in
|
||||
cursor.fetchall()]
|
||||
|
||||
|
||||
# 新增表
|
||||
def add_table(name, description, user_id):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO ai_reports_tables (name, description, create_by)
|
||||
VALUES (%s, %s, %s)
|
||||
RETURNING id
|
||||
""",
|
||||
(name, description, user_id)
|
||||
)
|
||||
new_id = cursor.fetchone()[0] # 取返回的 id
|
||||
return new_id
|
||||
|
||||
|
||||
# 获取字段
|
||||
def get_fields_by_table_id(table_id):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"SELECT id, name, type, description, is_active FROM ai_reports_fields WHERE table_id = %s",
|
||||
(table_id,),
|
||||
)
|
||||
return [{"id": row[0], "name": row[1], "type": row[2], "description": row[3], "is_active": row[4]} for row
|
||||
in cursor.fetchall()]
|
||||
|
||||
|
||||
# 新增字段
|
||||
def add_field(name, type, description, is_active, table_id, user_id):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"INSERT INTO ai_reports_fields (name,type,description, is_active, create_by, table_id) VALUES (%s, %s, %s, %s, %s, %s) RETURNING id",
|
||||
(name, type, description, is_active, user_id, table_id)
|
||||
)
|
||||
new_id = cursor.fetchone()[0] # 取返回的 id
|
||||
return new_id
|
||||
|
||||
|
||||
# 新增报表智能体
|
||||
def insert_bot(title: str, description: str, welcome_words: str, ai_personality: str, available_module: str,
|
||||
available_report_tables: str, available_kn_bases: str, user_id: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
available_roles = json.dumps(['user'])
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO ai_chat_profiles
|
||||
(available_module,available_roles, title, description, welcome_words, ai_personality, available_report_tables, available_kn_bases, created_by, created_at)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, now())
|
||||
RETURNING id
|
||||
""",
|
||||
(available_module, available_roles, title, description, welcome_words, ai_personality,
|
||||
available_report_tables, available_kn_bases, user_id)
|
||||
)
|
||||
report_id = cursor.fetchone()[0]
|
||||
return report_id
|
||||
|
||||
|
||||
# 更新报表智能体
|
||||
def update_bot(id: str, title: str, description: str, welcome_words: str, ai_personality: str, available_module: str,
|
||||
available_report_tables: str, available_kn_bases: str, user_id: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute("""
|
||||
UPDATE ai_chat_profiles
|
||||
SET title = %s,
|
||||
description = %s,
|
||||
ai_personality = %s,
|
||||
welcome_words = %s,
|
||||
available_report_tables = %s,
|
||||
available_kn_bases = %s,
|
||||
available_module = %s,
|
||||
updated_at = NOW(),
|
||||
updated_by = %s
|
||||
WHERE id = %s
|
||||
""",
|
||||
(title, description, ai_personality, welcome_words, available_report_tables,
|
||||
available_kn_bases, available_module, user_id, id)
|
||||
)
|
||||
|
||||
|
||||
# ————————————————————————————————————————————————————知识库———————————————————————————————
|
||||
def get_available_knowledge_bases(available_module: str):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id, name, description, is_active
|
||||
FROM ai_knowledge
|
||||
WHERE available_module::jsonb @> %s::jsonb
|
||||
""",
|
||||
(f'["{available_module}"]',)
|
||||
)
|
||||
|
||||
return [{"id": row[0], "name": row[1], "description": row[2], "is_active": row[3]} for row in
|
||||
cursor.fetchall()]
|
||||
|
||||
|
||||
def add_knowledge_base(name, description, user_id):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO ai_knowledge (name, description, created_by, created_at)
|
||||
VALUES (%s, %s, %s, now())
|
||||
RETURNING id
|
||||
""",
|
||||
(name, description, user_id)
|
||||
)
|
||||
new_id = cursor.fetchone()[0] # 取返回的 id
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy import text
|
||||
from config.pgDb import pg_pool
|
||||
from config.ssDb import mssql_pool
|
||||
from sqlalchemy import text
|
||||
|
||||
def executeSQL(sql: str):
|
||||
"""
|
||||
执行 SQL 并返回结果列表,每行是 dict
|
||||
"""
|
||||
with mssql_pool.getConn() as conn:
|
||||
result = conn.execute(text(sql))
|
||||
# SQLAlchemy 2.x 返回 Row 对象,转成 dict
|
||||
return [dict(row._mapping) for row in result]
|
||||
|
||||
def get_company_list(user_id: str):
|
||||
# 1️⃣ 从 PostgreSQL 获取 tenant_id
|
||||
with pg_pool.getConn() as pg_conn:
|
||||
with pg_conn.cursor() as cur:
|
||||
cur.execute("SELECT bbit_tenant_id FROM users WHERE id = %s", (user_id,))
|
||||
row = cur.fetchone()
|
||||
tenant_id = row[0] if row else None
|
||||
|
||||
# 2️⃣ 从 SQL Server 查询租户信息
|
||||
if tenant_id:
|
||||
query = text("SELECT Id, Name FROM dbo.POC_TENANTS WHERE Id = :tenant_id")
|
||||
params = {"tenant_id": tenant_id}
|
||||
else:
|
||||
query = text("SELECT Id, Name FROM dbo.POC_TENANTS")
|
||||
params = {}
|
||||
|
||||
with mssql_pool.getConn() as mssql_conn:
|
||||
result = mssql_conn.execute(query, params)
|
||||
return [{"id": str(row[0]), "name": row[1]} for row in result.fetchall()]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user