Compare commits

7 Commits

Author SHA1 Message Date
雷雨
655a3cd41f feat:南网指标短语替换 2025-12-04 15:56:52 +08:00
雷雨
e767a9ecaa feat:示例修改 2025-12-03 11:51:59 +08:00
雷雨
721ea07652 feat:嵌入模型整改 2025-12-02 17:31:02 +08:00
雷雨
a2309606bf feat:增加预制问题-答案 2025-12-02 17:26:21 +08:00
yujj128
35da349712 Merge branch 'dev_graph' of http://106.13.42.156:33077/lei_y601/sqlbot_agent into dev_graph 2025-12-02 16:06:42 +08:00
yujj128
4e4941d5d4 Timestamp时间写入问题修复 2025-12-02 16:03:57 +08:00
雷雨
b98faab961 feat:dockerfile增加sqlite3依赖 2025-11-29 09:43:23 +08:00
10 changed files with 385 additions and 53 deletions

View File

@@ -3,7 +3,7 @@ WORKDIR /app
COPY . /app
ENV TZ=Asia/Shanghai \
LANG=C.UTF-8
RUN rm -rf logs .git .idea .venv && apt-get update && apt-get install -y vim curl openssl libssl-dev && pip install -r requirement.txt -i https://mirrors.aliyun.com/pypi/simple/
RUN rm -rf logs .git .idea .venv && apt-get update && apt-get install -y vim curl openssl libssl-dev sqlite3 && pip install -r requirement.txt -i https://mirrors.aliyun.com/pypi/simple/
RUN mkdir -p /app/logs && touch /app/logs/sqlbot.log && rm -rf *.whl
EXPOSE 8084
CMD ["python","main_service.py"]

View File

@@ -12,9 +12,9 @@ from decouple import config
from template.template import get_base_template
from util.utils import extract_nested_json, check_and_get_sql, get_chart_type_from_sql_answer
from datetime import datetime
from util import train_ddl,utils
from util import train_ddl, utils
from util.pre_question_answer import merged_dict
gen_history_llm = ChatOpenAI(
model=config('CHAT_MODEL_NAME', default=''),
@@ -37,6 +37,8 @@ gen_sql_llm = ChatOpenAI(
'''
用于生成sql,生成图表的agent上下文
'''
class SqlAgentState(TypedDict):
user_question: str
rewritten_user_question: Optional[str]
@@ -52,9 +54,13 @@ class SqlAgentState(TypedDict):
sql_retry_count: int
chart_retry_count: int
'''
基于上下文,历史消息,重写用户问题
'''
def _rewrite_user_question(state: SqlAgentState) -> dict:
logger.info(f"user:{state.get('user_id', '1')} ---------------进入 _rewrite_user_question 节点---------------")
user_question = state['user_question']
@@ -76,6 +82,17 @@ def _gen_sql(state: SqlAgentState) -> dict:
logger.info(f"user:{state.get('user_id', '1')} ---------------进入 _gen_sql 节点---------------")
question = state.get('rewritten_user_question', state['user_question'])
service = vn
# 预制问题-答案,后期如模型效果好,可以考虑删除
if state.get('user_question', '') in merged_dict.keys():
logger.info(f"预制问题-答案-】-{state.get('user_question', '')}-hit")
r = merged_dict[state.get('user_question', '')]
r['success'] = True
return {'gen_sql_result': r, "sql_retry_count": 0, "gen_sql_error": ""}
if state.get('rewritten_user_question', '') in merged_dict.keys():
r = merged_dict[state.get('rewritten_user_question', '')]
r['success'] = True
return {'gen_sql_result': r, "sql_retry_count": 0, "gen_sql_error": ""}
question_sql_list = service.get_similar_question_sql(question)
if question_sql_list and len(question_sql_list) > 3:
question_sql_list = question_sql_list[:3]
@@ -97,7 +114,7 @@ def _gen_sql(state: SqlAgentState) -> dict:
logger.info(f"gensql result: {result}")
result = orjson.loads(result)
retry = state.get("sql_retry_count", 0) + 1
return {'gen_sql_result': result, "sql_retry_count": retry,"gen_sql_error":""}
return {'gen_sql_result': result, "sql_retry_count": retry, "gen_sql_error": ""}
except Exception as e:
import traceback
traceback.print_exc()
@@ -122,7 +139,8 @@ def _gen_chart(state: SqlAgentState) -> dict:
[{'role': 'system', 'content': sys_char_temp}, {'role': 'user', 'content': user_char_temp}]).text()
rr = utils.remove_think_tags(rr)
retry = state.get("chart_retry_count", 0) + 1
return {"chart_retry_count": retry, 'gen_chart_result': orjson.loads(extract_nested_json(rr)),"gen_chart_error":""}
return {"chart_retry_count": retry, 'gen_chart_result': orjson.loads(extract_nested_json(rr)),
"gen_chart_error": ""}
except Exception as e:
import traceback
traceback.print_exc()
@@ -183,4 +201,4 @@ memory = MemorySaver()
sql_chart_agent = workflow.compile(checkpointer=memory)
# png_data=sql_chart_agent .get_graph().draw_mermaid_png()
# with open("D://graph.png", "wb") as f:
# f.write(png_data)
# f.write(png_data)

View File

@@ -320,8 +320,8 @@ def update_question_feed_back():
update_user_feedBack(id, '', user_feedback)
return jsonify({"type": "success"})
except Exception as e:
logger.error(f"查询预制问题失败 failed:{e}")
return jsonify({"type": "error", "error": f'查询预制问题失败:{str(e)}'})
logger.error(f"保存问题反馈失败 failed:{e}")
return jsonify({"type": "error", "error": f'保存问题反馈失败:{str(e)}'})
@app.flask_app.route("/yj_sqlbot/api/v0/gen_graph_question", methods=["GET"])
@@ -383,8 +383,9 @@ def gen_graph_question():
return jsonify(data)
except Exception as e:
traceback.print_exc()
logger.error(f"查询预制问题失败 failed:{e}")
return jsonify({"type": "error", "error": f'查询预制问题失败:{str(e)}'})
logger.error(f"sql及图表生成环节异常 failed:{str(e)}")
update_conversation(id=id, answer={'type_error': 'error', 'error':f'sql及图表生成环节异常:{str(e)}' })
return jsonify({"type": "error", "error": f'sql及图表生成环节异常:{str(e)}'})
@app.flask_app.route("/yj_sqlbot/api/v0/run_sql_3", methods=["GET"])
@@ -438,9 +439,9 @@ def run_sql_3():
summary = rr.get('summary', '')
run_sql_error = rr.get('run_sql_error', '')
logger.debug(f"data type is {type(data)} data is {data} summary is {summary}")
if data and not run_sql_error:
if not run_sql_error:
update_conversation(id=id, answer={'data': data,'summary':summary})
elif run_sql_error:
else:
update_conversation(id=id, answer={'type_error':'error','error':"sql执行失败"})
logger.info(f"run_Sql finish run_sql_error => {run_sql_error}")
return jsonify(
@@ -452,7 +453,8 @@ def run_sql_3():
)
except Exception as e:
logger.error(f"run sql failed:{e}")
return jsonify({"type": "sql_error", "error": str(e)})
update_conversation(id=id, answer={'type_error': 'error', 'error': f'run sql环节异常 {str(e)}'})
return jsonify({"type": "sql_error", "error":f'run sql环节异常 {str(e)}'})
@app.flask_app.route("/yj_sqlbot/api/v0/get_history", methods=["GET"])

View File

@@ -1,8 +1,8 @@
import json
from datetime import datetime
import pandas as pd
from db_util.db_main import Conversation, SqliteSqlalchemy
import logging
from util.utils import custom_json_serializer
logger = logging.getLogger(__name__)
@@ -72,11 +72,27 @@ def update_conversation(id: str, sql=None, question=None, chart_cfg=None, meta=N
meta = json.dumps(meta, ensure_ascii=False)
update_data['meta'] = meta
if answer is not None:
if isinstance(answer, dict):
logger.info("answer dict")
answer_df = pd.DataFrame(answer)
answer = answer_df.to_json(orient='records', date_format='iso', force_ascii=False)
# answer = json.dumps(answer, ensure_ascii=False)
if isinstance(answer, (dict, list)):
# 直接使用JSON序列化避免DataFrame转换
try:
logger.info("json序列化")
answer = json.dumps(answer, ensure_ascii=False, default=custom_json_serializer)
logger.info(f"answer JSON: {answer}")
except Exception as e:
logger.error(f"JSON序列化失败,字符串化: {e}")
answer = str(answer)
else:
logger.info("其他类型直接转换为字符串")
answer = str(answer)
# if isinstance(answer, dict):
# logger.info("answer dict")
# answer_df = pd.DataFrame(answer)
# # answer_df = answer_df[0]
# answer = answer_df.to_json(orient='records', date_format='iso', force_ascii=False)
# answer = answer.rstrip(']')
# answer = answer.lstrip('[')
# logger.info(f"answer {answer}")
# # answer = json.dumps(answer, ensure_ascii=False)
update_data['answer'] = answer
if update_data:
result = session.query(Conversation).filter(Conversation.id == id).update(update_data)

View File

@@ -492,8 +492,8 @@ class CustomQdrant_VectorStore(Qdrant_VectorStore):
request_body = {
"model": self.embedding_model_name,
"encoding_format": "float",
# "input": [data],
"sentences":[data]
"input": [data],
#"sentences":[data]
}
#硅基流动的beg3
# request_body = {
@@ -510,27 +510,23 @@ class CustomQdrant_VectorStore(Qdrant_VectorStore):
# logger.info(f"request_body:{request_body}")
request_body.update(kwargs)
#AI中台的beg3
response = requests.post(
url=f"{self.embedding_api_base}",
json=request_body,
headers={"Authorization": f"Bearer {self.embedding_api_key}", 'Content-Type': 'application/json'},
)
#硅基流动的
# response = requests.post(
# url=f"{self.embedding_api_base}/v1/embeddings",
# json=request_body,
# headers={"Authorization": f"Bearer {self.embedding_api_key}", 'Content-Type': 'application/json'},
# )
response = requests.post(
url=f"{self.embedding_api_base}/v1/embeddings",
json=request_body,
headers={"Authorization": f"Bearer {self.embedding_api_key}", 'Content-Type': 'application/json'},
)
if response.status_code != 200:
raise RuntimeError(
f"Failed to create the embeddings, detail: {_get_error_string(response)}"
)
result = response.json()
# logger.info("embedding result:{0}".format(result))
embeddings = result['embeddings']
# embeddings = result['data'][0]['embedding']
return embeddings[0]
# return embeddings
#embeddings = result['embeddings']
embeddings = result['data'][0]['embedding']
#return embeddings[0]
return embeddings
class CustomVanna(CustomQdrant_VectorStore, OpenAICompatibleLLM):
def __init__(self, llm_config=None, vector_store_config=None):

View File

@@ -75,7 +75,6 @@ template:
</rule>
<rule>
<rule-title>术语标准化规则</rule-title>
<rule-detail>
数信中心和数信部都是部门,而非单位
</rule-detail>
@@ -86,7 +85,15 @@ template:
internal_dept和internal_unit的字段值是内部部门和内部单位编号而非名称涉及内部单位或部门时需要在部门表中递归查询
例如:"internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START WITH ("name" || "shortname") LIKE '%数信中心%' AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%' CONNECT BY PRIOR "id" = "parentid")
</rule-detail>
<rule-detail>
时间范围参考
上午 (Morning): 06:00:00 - 11:59:59
中午 (Noon): 12:00:00 - 13:59:59
下午 (Afternoon): 14:00:00 - 17:59:59
傍晚 (Evening): 18:00:00 - 19:59:59
晚上 (Night): 20:00:00 - 23:59:59
深夜 (Late Night): 00:00:00 - 05:59:59
</rule-detail>
</rule>
<rule>
<rule-title>聚合与计算</rule-title>
@@ -565,6 +572,7 @@ template:
|---|---|---|
| 数信部 | 数字信息部 | 如果匹配,则替换 |
| 安质部 | 安全质量部 | 如果匹配,则替换 |
| 南网 | 南方电网 | 如果匹配,则替换 |
# 输出格式要求

224
util/pre_question_answer.py Normal file
View File

@@ -0,0 +1,224 @@
q_a = {
"数信部上周有哪些人加班": {'sql': '''
SELECT DISTINCT p."id" AS "id",
p."code" AS "工号",
p."name" AS "姓名",
p."work_unit" AS "工作单位",
CASE WHEN ps."status" = '1008' THEN '加班' ELSE '其他' END AS "状态"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
JOIN "YJOA_APPSERVICE_DB"."t_yj_person_status" ps
ON p."code" = ps."person_id"
JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p."internal_dept" = o."id"
WHERE p."internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" || "shortname" LIKE '%数字信息部%') AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%'
CONNECT BY PRIOR "id" = "parentid")
AND p."dr" = 0
AND ps."status" = '1008'
AND ps."date_value" >= TRUNC(SYSDATE) - (TO_CHAR(SYSDATE
, 'd') - 1 + 7)
AND ps."date_value" <= TRUNC(SYSDATE) - (TO_CHAR(SYSDATE
, 'd') - 1) LIMIT 1000
''', 'chart-type': 'table'}
,
"数信部上周有哪些人迟到": {'sql':'''
SELECT p."id" AS "id",
p."code" AS "工号",
p."name" AS "姓名",
p."work_unit" AS "工作单位",
CASE
WHEN ps."status" = '1006' THEN '迟到早退'
WHEN ps."status" = '1009' THEN '迟到'
WHEN ps."status" = '6002' THEN 'am迟到pm在岗'
WHEN ps."status" = '6004' THEN 'am迟到pm缺勤'
ELSE ps."status" END AS "状态"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
INNER JOIN "YJOA_APPSERVICE_DB"."t_yj_person_status" ps
ON p."code" = ps."person_id"
WHERE ps."status" IN ('1006', '1009', '6002', '6004')
AND ps."date_value" >= TRUNC(SYSDATE) - (TO_CHAR(SYSDATE, 'd') - 1 + 7)
AND ps."date_value" <= TRUNC(SYSDATE) - (TO_CHAR(SYSDATE, 'd') - 1)
AND p."internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" || "shortname" LIKE '%数字信息部%' AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%')
CONNECT BY PRIOR "id" = "parentid") AND p."dr" = 0 AND ps."dr" = 0 LIMIT 1000
''','chart-type': 'table'},
"数信部本周有哪些人旷工": {'sql':'''
SELECT p."id" AS "id",
p."code" AS "工号",
p."name" AS "姓名",
p."work_unit" AS "工作单位",
CASE WHEN ps."status" = '1005' THEN '旷工' ELSE ps."status" END AS "状态"
FROM "YJOA_APPSERVICE_DB"."t_yj_person_status" ps
INNER JOIN "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
ON p."code" = ps."person_id"
WHERE ps."status" = '1005'
AND ps."date_value" >= TRUNC(SYSDATE) - (TO_CHAR(SYSDATE, 'd') - 1)
AND ps."date_value" <= TRUNC(SYSDATE) - (TO_CHAR(SYSDATE, 'd') - 1) + 7
AND ps."dr" = 0
AND p."dr" = 0
AND p."internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" || "shortname" LIKE '%数字信息部%' OR "name" || "shortname" LIKE '%数信中心%') AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%'
CONNECT BY PRIOR "id" = "parentid")
ORDER BY ps."date_value" DESC LIMIT 1000
''','chart-type': 'table'},
'数信部员工连续在藏天数查询': {'sql':'''
SELECT pt."year" AS "年份",
p."code" AS "人员编号",
pt."continuous_in_tibet_days" AS "连续在藏天数",
p."name" AS "姓名",
o."name" AS "部门"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
INNER JOIN "YJOA_APPSERVICE_DB"."t_yj_person_in_tibat" pt
ON p."code" = pt."person_id"
INNER JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p."internal_dept" = o."id"
WHERE p."dr" = 0
AND pt."dr" = 0
AND p."internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" || "shortname" LIKE '%数字信息部%' AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%')
CONNECT BY PRIOR "id" = "parentid")
ORDER BY pt."year" DESC, pt."continuous_in_tibet_days" DESC LIMIT 1000
''','chart-type': 'table'}
,
'数信中心员工累计在藏天数前20名': {'sql':'''
SELECT p."code" AS "人员编号",
p."name" AS "姓名",
o."name" AS "部门",
SUM(pt."count_in_tibat") AS "累计在藏天数"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
INNER JOIN "YJOA_APPSERVICE_DB"."t_yj_person_in_tibat" pt
ON p."code" = pt."person_id"
INNER JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p."internal_dept" = o."id"
WHERE p."dr" = 0
AND pt."dr" = 0
AND p."internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" || "shortname" LIKE '%数信中心%' AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%')
CONNECT BY PRIOR "id" = "parentid")
GROUP BY p."code", p."name", o."name"
ORDER BY SUM (pt."count_in_tibat") DESC LIMIT 20
''','chart-type': 'bar'},
'数信部员工昨日打卡记录查询':{'sql': '''
SELECT a."person_name" AS "person_name",
p."code" AS "employee_code",
a."attendance_time" AS "attendance_time",
a."attendance_address" AS "attendance_address",
CASE
WHEN a."status" = 1 THEN '在岗'
WHEN a."status" = 2 THEN '出差'
WHEN a."status" = 3
THEN '休假' END AS "status_desc",
CASE
WHEN a."enter_or_exit" = 1 THEN ''
WHEN a."enter_or_exit" = 2
THEN '' END AS "entry_exit",
o."name" AS "department_name"
FROM "YJOA_APPSERVICE_DB"."t_yj_person_attendance" a
JOIN "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
ON a."person_id" = p."code"
JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p."internal_dept" = o."id"
WHERE a."dr" = 0
AND p."dr" = 0
AND a."attendance_time" >= TRUNC(SYSDATE - 1)
AND a."attendance_time" < TRUNC(SYSDATE)
AND o."id" IN (SELECT o2."id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" o2
START WITH (o2."name" LIKE '%数字信息部%'
OR o2."shortname" LIKE '%数字信息部%')
AND o2."dr" = 0
AND o2."enable" = 1
AND o2."code" LIKE '%CYJ%'
CONNECT BY PRIOR o2."id" = o2."parentid")
ORDER BY a."attendance_time" DESC LIMIT 1000
''','chart-type': 'table'},
'数信中心员工昨日考勤查询':{'sql': '''
SELECT p."code" AS "工号",
p."name" AS "姓名",
o."name" AS "部门名称",
ps."date_value" AS "日期",
CASE
WHEN ps."status" = '1001' THEN '在岗'
WHEN ps."status" = '1002' THEN '出差'
WHEN ps."status" = '1003' THEN '休假,请假'
WHEN ps."status" = '1005' THEN '旷工'
WHEN ps."status" = '1006' THEN '迟到,早退'
WHEN ps."status" = '1007' THEN '休息日'
WHEN ps."status" = '1008' THEN '加班'
WHEN ps."status" = '1009' THEN '迟到'
WHEN ps."status" = '4001' THEN 'am在岗pm缺勤'
WHEN ps."status" = '4002' THEN 'am缺勤pm在岗'
WHEN ps."status" = '6001' THEN 'am在岗pm早退'
WHEN ps."status" = '6002' THEN 'am迟到pm在岗'
WHEN ps."status" = '6004' THEN 'am迟到pm缺勤'
WHEN ps."status" = '4006' THEN 'am缺勤pm早退'
ELSE ps."status" END AS "人员状态"
FROM "YJOA_APPSERVICE_DB"."t_yj_person_status" ps
JOIN "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
ON ps."person_id" = p."code"
JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p."internal_dept" = o."id"
WHERE o."id" IN (SELECT id FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" LIKE '%数信中心%' OR "shortname" LIKE '%数信中心%') AND "enable" = 1 AND "dr" = 0 AND "code" LIKE '%CYJ%'
CONNECT BY PRIOR "id" = "parentid")
AND ps."date_value" = TO_CHAR(SYSDATE - 1
, 'YYYY-MM-DD')
AND ps."dr" = 0
AND p."dr" = 0
ORDER BY ps."date_value" DESC LIMIT 1000
''','chart-type': 'table'},
'外部单位人数最多的前五家是哪几个': {'sql':'''
SELECT o.name AS "外部单位名称", COUNT(p.id) AS "员工人数"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
INNER JOIN "YJOA_APPSERVICE_DB"."t_pr3rl2oj_outsourcing_org_new" o
ON p.external_unit = o.id
WHERE p.dr = 0
GROUP BY o.name
ORDER BY COUNT(p.id) DESC LIMIT 5
''','chart-type': 'column'},
'数信部员工10月在林芝工作天数排行': {'sql':'''
SELECT p."code" AS "工号",
p."name" AS "姓名",
COUNT(DISTINCT TO_CHAR(a."attendance_time", 'yyyy-MM-dd')) AS "在林芝工作天数"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
LEFT JOIN "YJOA_APPSERVICE_DB"."t_yj_person_attendance" a
ON p."code" = a."person_id"
LEFT JOIN "YJOA_APPSERVICE_DB"."t_yj_person_ac_area" ac
ON a."access_control_point" = ac."ac_point"
WHERE p."dr" = 0
AND a."dr" = 0
AND ac."region" = 5
AND
p."internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" LIKE '%数字信息部%' OR "shortname" LIKE '%数字信息部%') AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%'
CONNECT BY PRIOR "id" = "parentid")
AND TO_CHAR(a."attendance_time"
, 'yyyy-MM') = '2025-10'
GROUP BY p."code", p."name"
ORDER BY "在林芝工作天数" DESC LIMIT 1000
''','chart-type': 'bar'},
'数信中心截止目前满足休假条件的员工有哪些': {'sql':'''
SELECT pt."year" AS "年份",
p."code" AS "人员编号",
pt."continuous_in_tibet_days" AS "连续在藏天数",
p."name" AS "姓名",
o."name" AS "部门"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
INNER JOIN "YJOA_APPSERVICE_DB"."t_yj_person_in_tibat" pt
ON p."code" = pt."person_id"
INNER JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p."internal_dept" = o."id"
WHERE p."dr" = 0
AND pt."dr" = 0
AND pt."continuous_in_tibet_days" >= 22
AND p."internal_dept" IN
(SELECT id FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" LIKE '%数信中心%' OR "shortname" LIKE '%数信中心%') AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%'
CONNECT BY PRIOR "id" = "parentid")
ORDER BY pt."continuous_in_tibet_days" DESC
''','chart-type': 'table'}
}
q_a_extent = {
"数字信息部上周有哪些人加班": q_a['数信部上周有哪些人加班'],
"数字信息部上周有哪些人迟到": q_a['数信部上周有哪些人迟到'],
"数字信息部本周有哪些人旷工": q_a['数信部本周有哪些人旷工'],
"数字信息部员工连续在藏天数查询": q_a['数信部员工连续在藏天数查询'],
"数字信息部员工昨日打卡记录查询": q_a['数信部员工昨日打卡记录查询'],
"数字信息部10月在林芝工作天数排行": q_a['数信部员工10月在林芝工作天数排行'],
}
merged_dict = q_a | q_a_extent

View File

@@ -26,7 +26,7 @@ org_and_attend_q_a = [
}, {
"question": "xx中心10月有哪些人迟到",
"answer": '''
SELECT p."id" AS "id",
SELECT
p."code" AS "code",
p."name" AS "name",
CASE WHEN ps."status" = '1006' THEN '迟到/早退' ELSE ps."status" END AS "status"
@@ -48,7 +48,7 @@ org_and_attend_q_a = [
{
"question": "xx中心10月有哪些人出差",
"answer": '''
SELECT p."id" AS "id",
SELECT
p."code" AS "code",
p."name" AS "name",
CASE WHEN ps."status" = '1002' THEN '出差' ELSE ps."status" END AS "status"
@@ -70,7 +70,7 @@ org_and_attend_q_a = [
{
"question": "xx中心10月有哪些人旷工",
"answer": '''
SELECT p."id" AS "id",
SELECT
p."code" AS "code",
p."name" AS "name",
CASE WHEN ps."status" = '1002' THEN '旷工' ELSE ps."status" END AS "status"
@@ -92,7 +92,7 @@ org_and_attend_q_a = [
{
"question": "xx中心10月有哪些人请假",
"answer": '''
SELECT p."id" AS "id",
SELECT
p."code" AS "code",
p."name" AS "name",
CASE WHEN ps."status" = '1003' THEN '请假' ELSE ps."status" END AS "status"
@@ -120,7 +120,7 @@ org_and_attend_q_a = [
COUNT(ps.id) AS "late_count"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p.internal_dept = o.id
JOIN "YJOA_APPSERVICE_DB"."t_yj_person_status" ps ON p.id = ps.person_id
JOIN "YJOA_APPSERVICE_DB"."t_yj_person_status" ps ON p.code = ps.person_id
WHERE p.dr = 0
AND ps.dr = 0
AND ps.status in ('1006','1009','6002','6004')
@@ -243,7 +243,7 @@ org_and_attend_q_a = [
{
"question": "xx中心10月有哪些人加班",
"answer": '''
SELECT p."id" AS "id",
SELECT
p."code" AS "code",
p."name" AS "name",
CASE WHEN ps."status" = '1008' THEN '加班' ELSE ps."status" END AS "status"
@@ -262,24 +262,18 @@ org_and_attend_q_a = [
"tags": ["员工", "部门", "考勤", "加班"],
"category": "考勤管理"
},{
'question':'xx部有哪些员工',
'question':'xx部有哪些正式员工',
'answer':'''
SELECT p."id" AS "id",
SELECT
p."code" AS "工号",
p."name" AS "姓名",
o."name" AS "单位",
CASE WHEN p."gender" = '1' THEN '' WHEN p."gender" = '2' THEN '' END AS "性别",
CASE
WHEN p."person_status" = '1' THEN '草稿'
WHEN p."person_status" = '2' THEN '审批中'
WHEN p."person_status" = '3' THEN '制卡中'
WHEN p."person_status" = '4' THEN '已入库'
WHEN p."person_status" = '5' THEN '停用' END AS "人员状态"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON p."internal_dept" = o."id"
WHERE p."internal_dept" IN (SELECT "id" FROM "IUAP_APDOC_BASEDOC"."org_orgs" START
WITH ("name" || "shortname") LIKE '%xx部%' AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%'
CONNECT BY PRIOR "id" = "parentid") AND p."dr" = 0
CONNECT BY PRIOR "id" = "parentid") AND p."dr" = 0 and p."person_type"='YG'
ORDER BY p."code" ASC LIMIT 1000
''',
"tags": ["员工", "部门",],

View File

@@ -224,6 +224,35 @@ question_and_answer = [
"tags": ["员工", "学历", "部门", "人数统计"],
"category": "学历分布统计"
},
{
"question": "XX部门员工学历或学位排行",
"answer": """
SELECT p."code" AS "员工编号",p."name" AS "姓名", o."name" AS "部门",
CASE WHEN p."highest_degree"='1' THEN '学士学位'
WHEN p."highest_degree"='2' THEN '硕士学位'
WHEN p."highest_degree"='3' THEN '博士学位'
ELSE '其他' END AS "学位",
p."graduate_school" AS "毕业院校"
FROM "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p
INNER JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o ON o."id"=p."internal_dept"
WHERE p."internal_dept" IN (
SELECT "id"
FROM "IUAP_APDOC_BASEDOC"."org_orgs"
START WITH ("name" || "shortname" LIKE '%数信中心%' AND "dr" = 0 AND "enable" = 1 AND "code" LIKE '%CYJ%')
CONNECT BY PRIOR "id" = "parentid")
AND p.dr=0
AND o.dr=0
AND p."person_type" = 'YG'
ORDER BY
CASE WHEN p."highest_degree" = '1' THEN 1
WHEN p."highest_degree" = '2' THEN 2
WHEN p."highest_degree" = '3' THEN 3
ELSE 0
END DESC LIMIT 1000
""",
"tags": ["员工", "学历", "部门", "人数统计"],
"category": "学历分布统计"
},
{
"question": "XX部门博士多少人",
"answer": '''
@@ -807,7 +836,34 @@ question_and_answer = [
"category": "工作地考勤统计分析"
},
{
"question": "本月XX中心各处室下迟到人次统计",
"answer": '''
SELECT o1."name" AS "处室名称", COUNT(DISTINCT ps."person_id") AS "迟到人数"
FROM "YJOA_APPSERVICE_DB"."t_yj_person_status" ps
JOIN "YJOA_APPSERVICE_DB"."t_pr3rl2oj_yj_person_database" p ON ps."person_id" = p."code"
JOIN "IUAP_APDOC_BASEDOC"."org_orgs" o1 ON p."internal_dept" = o1."id"
WHERE ps."status" IN ('1006','1009','6002','6004')
AND ps."date_value" LIKE '2025-11%'
AND ps."dr" = 0
AND p."dr" = 0
AND o1."dr" = 0
AND o1."enable" = 1
AND o1."code" LIKE '%CYJ%'
AND p."internal_dept"IN (
SELECT id
FROM "IUAP_APDOC_BASEDOC"."org_orgs"
START WITH ("name" LIKE '%数信中心%' OR "shortname" LIKE '%数信中心%')
AND "dr" = 0
AND "enable" = 1
AND "code" LIKE '%CYJ%'
CONNECT BY PRIOR "id" = "parentid")
GROUP BY o1."name"
ORDER BY "迟到人数" DESC LIMIT 1000
''',
"tags": ["员工", "部门", "考勤", "迟到","统计"],
"category": "各部门迟到统计分析"
},
{
"question": "张三9月在林芝上班期间有多少天早退了",
"answer": '''

View File

@@ -2,6 +2,10 @@ import logging
from typing import Optional
import re
from orjson import orjson
import pandas as pd
from pandas import Timestamp
from datetime import datetime, date
logger = logging.getLogger(__name__)
keywords = {
# "gender":{"1":"男","2":"女"},
@@ -107,3 +111,17 @@ def deal_result(data: list) -> list:
raise Exception(f"sql执行结果处理失败{str(e)}")
def custom_json_serializer(obj):
"""自定义JSON序列化器"""
if isinstance(obj, (Timestamp, pd.Timestamp)):
logger.info("format Timestamp")
return obj.isoformat()
elif isinstance(obj, (datetime, date)):
logger.info("format datetime")
return obj.isoformat()
elif pd.isna(obj):
logger.info("format NaN")
return None
else:
logger.error(f"unknown type {type(obj)}")
return str(obj)