xiaoshi_AI_userRecord_api.py 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. from flask import Flask, request, jsonify, Response,send_file,abort
  2. import os
  3. import requests
  4. from requests.exceptions import HTTPError
  5. import pymysql
  6. import json
  7. from dateutil import parser
  8. from datetime import datetime, timedelta
  9. import pytz
  10. import random
  11. import string
  12. import time
  13. from openpyxl import Workbook
  14. from openpyxl.chart import BarChart,LineChart, Reference
  15. from openpyxl.styles import Font, Alignment, PatternFill
  16. from openpyxl.utils import get_column_letter
  17. # 定时
  18. from apscheduler.schedulers.blocking import BlockingScheduler
  19. from flask_cors import CORS
  20. app = Flask(__name__)
  21. CORS(app)
  22. class Response1:
  23. def success(self,data,message='请求成功'):
  24. return {
  25. "code":200,
  26. "data":data,
  27. "message":message
  28. }
  29. def error(self,message='系统异常'):
  30. return {
  31. "code":500,
  32. "data":None,
  33. "message":message
  34. }
  35. def any(self,code,data,message):
  36. return {
  37. "code":code,
  38. "data":data,
  39. "message":message
  40. }
  41. requestResponse = Response1()
  42. file_prefix = 'file'
  43. workFlow_logs = {
  44. 'f815a6f2-4f8d-482c-b214-b8fd437ef12d':{
  45. "type":1,
  46. 'name':'权利要求解释及有益效果'
  47. },
  48. '01f7efbf-d23f-49f9-8ee4-740892c4f6a5':{
  49. "type":2,
  50. 'name':'OA答辩',
  51. 'emails':['gaochangkui@china-wispro.com']
  52. },
  53. 'a30f1218-bc9d-4f2a-985a-2386671a91dc':{
  54. "type":3,
  55. 'name':'生成说明书',
  56. 'emails':['lirenjie@china-wispro.com']
  57. },
  58. '1ca8efd1-b24a-4b7f-8853-001663bb56dc':{
  59. "type":2,
  60. 'name':'OA答辩',
  61. 'emails':['gaochangkui@china-wispro.com']
  62. }
  63. }
  64. chatFlow_logs = {
  65. '7f7812ce-89f4-4981-a55c-efe2e016cb36':{
  66. 'name':'技术交底书理解',
  67. 'emails':['lirenjie@china-wispro.com']
  68. },
  69. }
  70. #时间格式转换
  71. def formateDate(time_str="Thu, 07 Mar 2024 18:36:18 GMT",time_format = "%a, %d %b %Y %H:%M:%S GMT",formate='%Y-%m-%d %H:%M:%S'):
  72. # 解析时间字符串为datetime对象,并设置时区为GMT
  73. dt = ''
  74. if isinstance(time_str, datetime):
  75. dt = time_str
  76. else:
  77. dt = datetime.strptime(time_str, time_format)
  78. # 转换为所需的日期格式 YYYY-mm-dd
  79. formatted_date = dt.strftime(formate)
  80. return formatted_date
  81. def readAndWritePerson(users,userRecode_first,userRecode_end,useRecord_list,requestData):
  82. difyId = requestData.get('difyId')
  83. folder = getFilePath(difyId)
  84. json_file_path = f'{file_prefix}\{folder}\person-{folder}.json'
  85. personData = []
  86. data = {}
  87. removePerson = []
  88. useRecord = {}
  89. try:
  90. with open(json_file_path,'r',encoding='utf-8') as json_file:
  91. data = json.load(json_file)
  92. except FileNotFoundError:
  93. print(f"文件 {json_file_path} 未找到。")
  94. except json.JSONDecodeError:
  95. print(f"文件 {json_file_path} 不是有效的 JSON 格式。")
  96. except IOError as e:
  97. print(f"发生I/O错误: {e}")
  98. finally:
  99. personData = data.get('persons',[])
  100. removePerson = data.get('removePerson',["1","323","103","328"])
  101. useRecord = data.get('useRecord',{})
  102. # yesterday = formateDate(datetime.now() - timedelta(days=1),"%a, %d %b %Y %H:%M:%S GMT",'%Y-%m-%d')
  103. # yesterday = formateDate(requestData.get('startTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d')
  104. # useRecord[yesterday] = []
  105. for key,value in useRecord_list.items():
  106. if key in useRecord:
  107. continue
  108. else:
  109. useRecord[key] = value
  110. for user in users:
  111. id = str(user['id'])
  112. if id in removePerson:
  113. continue
  114. # if(user['personnelName']):
  115. # useRecord[yesterday].append(user['personnelName'])
  116. # else:
  117. # useRecord[yesterday].append(user['personnelUserName'])
  118. person_id = ''
  119. for person in personData:
  120. if(person['id'] == id):
  121. person_id = person['id']
  122. break
  123. if person_id:
  124. person['lastUseTime'] = userRecode_end[id]
  125. else:
  126. obj = {
  127. "name":user['personnelName'],
  128. "username":user['personnelUserName'],
  129. "id":id,
  130. "firstUseTime":userRecode_first[id],
  131. "lastUseTime":userRecode_end[id],
  132. "departmentId":user.get('departmentId',''),
  133. "departmentName":user.get('departmentName',''),
  134. }
  135. personData.append(obj)
  136. data['persons'] = personData
  137. data['useRecord'] = useRecord
  138. with open(json_file_path, 'w', encoding='utf-8') as json_file:
  139. # 将 Python 对象转换为 JSON 格式并写入文件
  140. json.dump(data, json_file, ensure_ascii=False, indent=4)
  141. return personData
  142. # 查询今日会话情况(调用dify日志)
  143. def fetch_data(page_size,data):
  144. token = data.get('token')
  145. difyId = data.get('difyId')
  146. headers={
  147. 'Content-Type': 'application/json',
  148. 'Authorization':f"Bearer {token}"
  149. }
  150. params1 = {
  151. "page": page_size,
  152. "limit": 10,
  153. "start": formateDate(data.get('startTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d %H:%M'),#时间需要修改
  154. "end": formateDate(data.get('endTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d %H:%M'),#时间需要修改
  155. "sort_by": "created_at",
  156. "annotation_status": "all"
  157. }
  158. url = f"http://192.168.2.24/console/api/apps/{difyId}/chat-conversations"
  159. response = requests.get(url, headers=headers,params=params1)
  160. response.raise_for_status()
  161. return response.json()
  162. def getChatMessageRecord(conversation_id,data):
  163. token = data.get('token')
  164. difyId = data.get('difyId')
  165. headers={
  166. 'Content-Type': 'application/json',
  167. 'Authorization':f"Bearer {token}"
  168. }
  169. url = f"http://192.168.2.24/console/api/apps/{difyId}/chat-messages"
  170. params1 = {
  171. "limit":10,
  172. "conversation_id":conversation_id
  173. }
  174. response = requests.get(url, headers=headers,params=params1)
  175. response.raise_for_status()
  176. return response.json()
  177. # 获取所有人员信息
  178. def get_personByIds(ids):
  179. url = "http://47.116.194.135:8880/permission/api/system/getPersonnelByIds"
  180. params1 = {
  181. "ids":ids
  182. }
  183. headers={
  184. 'Content-Type': 'application/json',
  185. }
  186. response = requests.post(url, headers=headers,data=json.dumps(ids))
  187. response.raise_for_status()
  188. return response.json()
  189. # 获取两个日期之间的所有日期
  190. def get_dates_between(start_date_str, end_date_str, date_format='%Y-%m-%d'):
  191. # 将字符串转换为 datetime 对象
  192. start_date = datetime.strptime(start_date_str, date_format)
  193. end_date = datetime.strptime(end_date_str, date_format)
  194. # 初始化一个空列表来存储日期
  195. date_list = []
  196. # 使用一个循环来生成日期范围
  197. current_date = start_date
  198. while current_date <= end_date:
  199. date_list.append(current_date.strftime(date_format))
  200. current_date += timedelta(days=1)
  201. return date_list
  202. # 获取活跃用户数数据
  203. def getActiveUser(requestData,data):
  204. sheetData = []
  205. # 写入表头
  206. sheetData.append(['时间','人数','人员'])
  207. useRecord = data.get('useRecord',{})
  208. for time, users in useRecord.items():
  209. user_len = len(users)
  210. if user_len != 0:
  211. sheetData.append([time,user_len,','.join(users)])
  212. return sheetData
  213. #获取对话记录数据
  214. def getChatRecord(requestData,data):
  215. sheetData = []
  216. # 写入表头
  217. sheetData.append(['序号','姓名','所属部门','提交文件','问题','答案','结果文件','时间'])
  218. # 写入数据
  219. num = 1
  220. for item in data:
  221. body = [num]
  222. fieldList = ['name','departmentName','file','input','answer','resultFile','time']
  223. for field in fieldList:
  224. if field in item:
  225. body.append(item[field])
  226. else:
  227. if field == 'file' or field == 'resultFile':
  228. body.append(
  229. {
  230. 'guid':'',
  231. 'originalName':''
  232. }
  233. )
  234. else:
  235. body.append('')
  236. sheetData.append(body)
  237. num = num + 1
  238. return sheetData
  239. # 分组
  240. def groupByField(data,field='id',fun=None):
  241. groupData = {}
  242. for item in data:
  243. value = ''
  244. if fun:
  245. value = fun(item[field])
  246. else:
  247. if field in item:
  248. value = item[field]
  249. else:
  250. value = "UnKnow"
  251. if value in groupData:
  252. groupData[value]['num'] = groupData[value]['num'] + 1
  253. else:
  254. groupData[value] = {}
  255. groupData[value]['data'] = []
  256. groupData[value]['num'] = 1
  257. groupData[value]['data'].append(item)
  258. return groupData
  259. # 时间转日期
  260. def timeToDate(time):
  261. date = formateDate(time,'%Y-%m-%d %H:%M:%S','%Y-%m-%d')
  262. return date
  263. # 新增新用户
  264. def getNewUserNum(requestData,data):
  265. sheetData = []
  266. # 写入表头
  267. sheetData.append(['时间','新用户数量','人员'])
  268. persons = data.get('persons',[])
  269. obj = groupByField(persons,'firstUseTime',timeToDate)
  270. for key ,value in obj.items():
  271. num = value['num']
  272. data2 = value['data']
  273. user = [person['name'] or person['username'] for person in data2]
  274. sheetData.append([key,num,','.join(user)])
  275. return sheetData
  276. #获取两个日期之间的间隔天数
  277. def getBetweenDay(date_str1,date_str2):
  278. date1 = datetime.strptime(date_str1, "%Y-%m-%d")
  279. date2 = datetime.strptime(date_str2, "%Y-%m-%d")
  280. # 计算两个日期之间的差异
  281. delta = date2 - date1
  282. # 获取间隔天数
  283. days_between = delta.days
  284. return days_between
  285. #用户存活率
  286. def getUserActive(requestData,data):
  287. sheetData = []
  288. # 写入表头
  289. sheetData.append(['未使用时长','数量','人员'])
  290. persons = data.get('persons',[])
  291. obj = groupByField(persons,'lastUseTime',timeToDate)
  292. today = formateDate(datetime.now() - timedelta(days=1),"%a, %d %b %Y %H:%M:%S GMT",'%Y-%m-%d')
  293. for key ,value in obj.items():
  294. num = value['num']
  295. data2 = value['data']
  296. user = [person['name'] or person['username'] for person in data2]
  297. betweenDay = getBetweenDay(key,today)
  298. sheetData.append([betweenDay,num,','.join(user)])
  299. return sheetData
  300. # 获取用户使用天数
  301. def getUseDays(data):
  302. useDays = {}
  303. for key,value in data.items():
  304. if len(value)>0:
  305. for item in value:
  306. if item in useDays:
  307. useDays[item] += 1
  308. else:
  309. useDays[item] = 1
  310. return useDays
  311. # 用户使用情况
  312. def getUserUsage(requestData,data):
  313. sheetData = []
  314. # 写入表头
  315. sheetData.append(['姓名','部门','首次使用时间','最后一次使用时间','使用天数'])
  316. persons = data.get('persons',[])
  317. useRecord = data.get('useRecord',{})
  318. useDays = getUseDays(useRecord)
  319. for person in persons:
  320. sheetData.append([person['name'],person['departmentName'],person['firstUseTime'],person['lastUseTime'],useDays[person['name']]])
  321. return sheetData
  322. # 部门使用情况
  323. def getDepartmentUsage(requestData,data):
  324. sheetData = []
  325. persons = data.get('persons',[])
  326. # 写入表头
  327. sheetData.append(['部门','部长','副部长','使用人数','人员'])
  328. departmentMessage=[]
  329. # 读取部门信息
  330. json_file_path = f'departmentMessage.json'
  331. try:
  332. with open(json_file_path,'r',encoding='utf-8') as json_file:
  333. fileData = json.load(json_file)
  334. departmentMessage = fileData.get('data',[])
  335. except FileNotFoundError:
  336. print(f"文件 {json_file_path} 未找到。")
  337. except json.JSONDecodeError:
  338. print(f"文件 {json_file_path} 不是有效的 JSON 格式。")
  339. except IOError as e:
  340. print(f"发生I/O错误: {e}")
  341. obj = groupByField(persons,'departmentId')
  342. for department in departmentMessage:
  343. departmentId = department['departmentId']
  344. users = []
  345. num = 0
  346. if departmentId in obj:
  347. department_obj = obj[departmentId]
  348. num = department_obj['num']
  349. department_data = department_obj['data']
  350. users = [person['name'] or person['username'] for person in department_data]
  351. sheetData.append([department['departmentName'],department['minister'],department['deputyMinister'],num,','.join(users)])
  352. return sheetData
  353. # 各分所使用情况
  354. def getAreaUsage(requestData,data):
  355. sheetData = []
  356. persons = data.get('persons',[])
  357. # 写入表头
  358. sheetData.append(['分所','总人数','使用人数','人员'])
  359. person_area = {}
  360. json_file_path = f'personnel_area.json'
  361. try:
  362. with open(json_file_path,'r',encoding='utf-8') as json_file:
  363. person_area = json.load(json_file)
  364. except FileNotFoundError:
  365. print(f"文件 {json_file_path} 未找到。")
  366. except json.JSONDecodeError:
  367. print(f"文件 {json_file_path} 不是有效的 JSON 格式。")
  368. except IOError as e:
  369. print(f"发生I/O错误: {e}")
  370. if not person_area:
  371. return sheetData
  372. person_area_data = person_area['data']
  373. # person_area_areas = person_area['areas']
  374. person_area_areas = set()
  375. person_area_data_nums = {}
  376. # 获取每个分所的人数
  377. for key,value in person_area_data.items():
  378. person_area_areas.add(value)
  379. if value in person_area_data_nums:
  380. person_area_data_nums[value] += 1
  381. else:
  382. person_area_data_nums[value] = 1
  383. for item in persons:
  384. person_id = item['id']
  385. if person_id in person_area_data:
  386. item['area'] = person_area_data[str(person_id)]
  387. obj = groupByField(persons,'area')
  388. for item in person_area_areas:
  389. num = 0
  390. area_name = item
  391. users = []
  392. if area_name in obj:
  393. obj_value = obj[area_name]
  394. num = obj_value['num']
  395. obj_data = obj_value['data']
  396. users = [person['name'] or person['username'] for person in obj_data]
  397. sheetData.append([area_name,person_area_data_nums[area_name] or 0,num,','.join(users)])
  398. # for key,value in obj.items():
  399. # num = value['num']
  400. # obj_data = value['data']
  401. # users = [person['name'] or person['username'] for person in obj_data]
  402. # sheetData.append([key,num,','.join(users)])
  403. return sheetData
  404. # 导出excel
  405. def exportExcel(chat_message_records,requestData,time_obj):
  406. difyId = requestData.get('difyId')
  407. # now_time = formateDate(datetime.now(),"%a, %d %b %Y %H:%M:%S GMT",'%Y-%m-%d')
  408. # 创建一个新的工作簿和工作表
  409. wb = Workbook()
  410. ws = wb.active
  411. # 删除原工作表
  412. if "Sheet" in wb.sheetnames:
  413. default_sheet = wb["Sheet"]
  414. wb.remove(default_sheet)
  415. #查询当前人员数据
  416. person_data = {}
  417. folder = getFilePath(difyId)
  418. json_file_path = f'{file_prefix}\{folder}\person-{folder}.json'
  419. try:
  420. with open(json_file_path,'r',encoding='utf-8') as json_file:
  421. person_data = json.load(json_file)
  422. except FileNotFoundError:
  423. print(f"文件 {json_file_path} 未找到。")
  424. except json.JSONDecodeError:
  425. print(f"文件 {json_file_path} 不是有效的 JSON 格式。")
  426. except IOError as e:
  427. print(f"发生I/O错误: {e}")
  428. data_for_sheets = {
  429. "活跃用户数":{
  430. "type":LineChart,
  431. "data":[],
  432. "fun":getActiveUser,
  433. "params":person_data
  434. },
  435. "新增新用户":{
  436. "type":LineChart,
  437. "data":[],
  438. "fun":getNewUserNum,
  439. "params":person_data
  440. },
  441. "用户死亡率":{
  442. "type":LineChart,
  443. "data":[],
  444. "fun":getUserActive,
  445. "params":person_data
  446. },
  447. "用户使用情况":{
  448. "type":'default',
  449. "data":[],
  450. "fun":getUserUsage,
  451. "params":person_data
  452. },
  453. "部门使用情况":{
  454. "type":'default',
  455. "data":[],
  456. "fun":getDepartmentUsage,
  457. "params":person_data
  458. },
  459. "分所使用情况":{
  460. "type":'default',
  461. "data":[],
  462. "fun":getAreaUsage,
  463. "params":person_data
  464. },
  465. "对话记录":{
  466. "type":'default',
  467. "data":[],
  468. "fun":getChatRecord,
  469. "params":chat_message_records,
  470. "file_index":4,
  471. "result_file_index":7
  472. }
  473. }
  474. hyperlink_font = Font(color="0000FF", underline="single")
  475. header_fill = PatternFill(start_color="8DB4E2", end_color="8DB4E2", fill_type="solid")
  476. download_file_url = 'https://xsip.cn/api/fileManager/downloadFile?fileId='
  477. # 向每个工作表插入数据
  478. for sheet_name, data in data_for_sheets.items():
  479. # 如果工作表不存在,则创建它
  480. sheet = None
  481. if sheet_name not in wb.sheetnames:
  482. sheet = wb.create_sheet(title=sheet_name)
  483. else:
  484. sheet = wb[sheet_name]
  485. if "fun" in data:
  486. if "params" in data:
  487. data['data'] = data['fun'](requestData,data['params'])
  488. else:
  489. data['data'] = data['fun'](requestData)
  490. # 写入数据到工作表
  491. for row_idx, row in enumerate(data['data'], start=1): # start=1 因为 Excel 行号从 1 开始
  492. for col_idx, value in enumerate(row, start=1):
  493. file_index = None
  494. result_file_index = None
  495. if 'file_index' in data:
  496. file_index = data['file_index']
  497. if 'result_file_index' in data:
  498. result_file_index = data['result_file_index']
  499. if row_idx != 1 and (col_idx == file_index or col_idx == result_file_index):#文件
  500. if 'originalName' in value and value['originalName']:
  501. link_cell = sheet.cell(row=row_idx, column=col_idx, value=value['originalName'])
  502. link_cell.hyperlink = download_file_url + value['guid']
  503. link_cell.font = hyperlink_font
  504. else:
  505. sheet.cell(row=row_idx, column=col_idx, value='')
  506. elif row_idx == 1:
  507. cell = sheet.cell(row=row_idx, column=col_idx, value=value)
  508. cell.alignment = Alignment(horizontal='center')
  509. cell.fill = header_fill
  510. else:
  511. sheet.cell(row=row_idx, column=col_idx, value=value)
  512. # 设置单元格垂直居中
  513. sheet.freeze_panes = 'A2'
  514. for row in sheet.iter_rows():
  515. for cell in row:
  516. cell.alignment = Alignment(vertical='center')
  517. # 设置行高为45
  518. for row in range(1, sheet.max_row + 1):
  519. sheet.row_dimensions[row].height = 45
  520. # 设置列宽自适应
  521. if sheet_name != "对话记录":
  522. for col in sheet.columns:
  523. max_length = 10
  524. column = col[0].column_letter # 获取列字母
  525. for cell in col:
  526. try:
  527. if len(str(cell.value)) > max_length:
  528. max_length = len(str(cell.value))
  529. except:
  530. pass
  531. adjusted_width = (max_length * 2)
  532. sheet.column_dimensions[column].width = adjusted_width
  533. if data['type'] != 'default':
  534. type = data.get('type','BarChart')
  535. try:
  536. chart = type()
  537. length = len(data['data'])
  538. # 定义数据范围(不包括标题行)
  539. data_values_rang = f"B2:B{length}"
  540. if(length == 2):
  541. data_values_rang = f"B2"
  542. data_values = Reference(sheet, range_string=f"{sheet_name}!{data_values_rang}")
  543. # data_values = Reference(sheet, min_col=2, min_row=2, max_col=2, max_row=length)
  544. # categories = Reference(sheet, min_col=1, min_row=2, max_row=length)
  545. categories_rang = f"A2:A{length}"
  546. if(length == 2):
  547. categories_rang = f"A2"
  548. categories = Reference(sheet, range_string=f"{sheet_name}!{categories_rang}")
  549. # 将数据和类别添加到图表
  550. chart.add_data(data_values, titles_from_data=False) # 如果数据有标题行,可以设置为 True
  551. chart.set_categories(categories)
  552. # 可选:设置图表标题和轴标签
  553. chart.title = data.get('title','')
  554. chart.x_axis.title = data.get('x','')
  555. chart.y_axis.title = data.get('y','')
  556. # 将图表添加到工作表(指定位置,例如从 E1 开始)
  557. lei = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
  558. first_data = data['data'][0]
  559. first_data_len = len(first_data)
  560. zimu = lei[first_data_len + 1]
  561. sheet.add_chart(chart, f"{zimu}2")
  562. except Exception as e:
  563. print(e)
  564. # 保存工作簿
  565. # file_name = f'{now_time}-{difyId}-使用情况.xlsx'
  566. file_name = time_obj['file_name']
  567. wb.save(file_name)
  568. return file_name
  569. def getDifyRecord1(data,time_obj):
  570. difyId = data.get('difyId')
  571. results = []
  572. # 获取时间范围内提问的人员以及首次提问时间和最后一次提问时间
  573. unique_userId = set()
  574. userRecode_first = {}#每个人第一次一次使用时间
  575. userRecode_end = {}#每个人最后一次使用时间
  576. if difyId not in workFlow_logs:
  577. # 查询时间范围内所有的提问记录
  578. page = 0
  579. currentResult = {
  580. 'has_more': True,
  581. }
  582. while True:
  583. if currentResult.get('has_more') != True:
  584. break
  585. # 发送请求
  586. page = page + 1
  587. try:
  588. currentResult = fetch_data(page,data)
  589. results.extend(currentResult.get('data'))
  590. finally:
  591. print('获取日志')
  592. for item in results:
  593. if 'from_end_user_session_id' in item: # 确保字典中有 'from_end_user_session_id' 键
  594. id = item['from_end_user_session_id']
  595. created_time = datetime.fromtimestamp(item['created_at'])
  596. unique_userId.add(id)
  597. if id in userRecode_first:
  598. userRecode_end[id] = formateDate(created_time)
  599. else:
  600. userRecode_first[id] = formateDate(created_time)
  601. userRecode_end[id] = formateDate(created_time)
  602. else:
  603. currentWorkFlow = workFlow_logs[difyId]
  604. params = {
  605. "startTime":data['startTime'],
  606. "endTime":data['endTime'],
  607. "type":currentWorkFlow['type'],
  608. }
  609. results = getSession(params)
  610. for item in results:
  611. id = item['from_end_user_session_id']
  612. created_time = item['time']
  613. unique_userId.add(id)
  614. if id in userRecode_first:
  615. userRecode_end[id] = created_time
  616. else:
  617. userRecode_first[id] = created_time
  618. userRecode_end[id] = created_time
  619. # 获取人员信息并保存
  620. unique_userId_List = list(unique_userId)
  621. persons = get_personByIds(unique_userId_List)
  622. departmentList = getDepartmentByPersonIds(unique_userId)
  623. persons_obj = {}
  624. person_dep = {}
  625. if(persons.get('code') == 200):
  626. persons_list = persons.get('data')
  627. # 获取人员部门
  628. if len(departmentList):
  629. for person in persons_list:
  630. personId = person['id']
  631. for department in departmentList:
  632. if personId == department['personId']:
  633. person['departmentName'] = department['departmentName']
  634. person['departmentId'] = department['departmentId']
  635. break
  636. for person in persons_list:
  637. person_id = person['id']
  638. if 'departmentName' in person:
  639. person_dep[str(person_id)] = person['departmentName']
  640. else:
  641. person_dep[str(person_id)] = ''
  642. if person['personnelName']:
  643. persons_obj[str(person_id)] = person['personnelName']
  644. else:
  645. persons_obj[str(person_id)] = person['personnelUserName']
  646. useRecord_list = {}#每日的使用人
  647. removePerson = ["1","323","103","328"]
  648. for item in results:
  649. created_time = ''
  650. created_time_date=''
  651. if difyId not in workFlow_logs:
  652. created_time = datetime.fromtimestamp(item['created_at'])
  653. created_time_date = formateDate(created_time,"%a, %d %b %Y %H:%M:%S GMT",'%Y-%m-%d')
  654. else:
  655. created_time = item['time']
  656. created_time_date = formateDate(created_time,"%Y-%m-%d %H:%M:%S",'%Y-%m-%d')
  657. if 'from_end_user_session_id' in item: # 确保字典中有 'from_end_user_session_id' 键
  658. id = item['from_end_user_session_id']
  659. if id in removePerson:
  660. continue
  661. name = ''
  662. if id in persons_obj:
  663. name = persons_obj[id]
  664. if created_time_date in useRecord_list:
  665. if name in useRecord_list[created_time_date]:
  666. continue
  667. else:
  668. useRecord_list[created_time_date].append(name)
  669. else:
  670. useRecord_list[created_time_date] = []
  671. useRecord_list[created_time_date].append(name)
  672. # 记录使用人员
  673. # if time_obj['is_same_day']:
  674. # print('进来了')
  675. readAndWritePerson(persons_list,userRecode_first,userRecode_end,useRecord_list,data)
  676. # 获取具体提问内容以及答案
  677. chat_message_records = []
  678. if difyId not in workFlow_logs:
  679. for chat_record in results:
  680. try:
  681. conversation_id = chat_record.get('id')
  682. user_id = chat_record['from_end_user_session_id']
  683. chat_message = getChatMessageRecord(conversation_id,data)
  684. chat_message_data = chat_message.get('data')
  685. for message in chat_message_data:
  686. created_time = datetime.fromtimestamp(message['created_at'])
  687. obj = {
  688. "input":message['query'],
  689. "answer":message['answer'],
  690. "answer_tokens":message['answer_tokens'],
  691. "conversation_id":message['conversation_id'],
  692. "id":user_id,
  693. "name":persons_obj[user_id],
  694. 'departmentName':person_dep[user_id],
  695. "time":formateDate(created_time)
  696. }
  697. chat_message_records.append(obj)
  698. finally:
  699. print('获取对话记录')
  700. else:
  701. for chat_record in results:
  702. user_id = chat_record['from_end_user_session_id']
  703. chat_record['id'] = user_id
  704. chat_record['name'] = persons_obj[user_id]
  705. chat_record['departmentName'] = person_dep[user_id]
  706. chat_message_records.append(chat_record)
  707. #导出
  708. file_name = exportExcel(chat_message_records,data,time_obj)
  709. return file_name
  710. # 对比两个时间是否是同一天
  711. def is_same_day_str(date_str1, date_str2, fmt="%Y-%m-%d"):
  712. date1 = datetime.strptime(date_str1, fmt)
  713. date2 = datetime.strptime(date_str2, fmt)
  714. return date1.date() == date2.date()
  715. #获取文件路径
  716. def getFilePath(difyId):
  717. folder = ''
  718. if difyId in workFlow_logs:
  719. folder = workFlow_logs[difyId]['name'] or 'file'
  720. elif difyId in chatFlow_logs:
  721. folder = chatFlow_logs[difyId]['name'] or 'file'
  722. return folder
  723. #获取待发送的邮箱
  724. def getEmails(difyId):
  725. emails = []
  726. if difyId in workFlow_logs:
  727. folder = workFlow_logs[difyId]['emails'] or []
  728. elif difyId in chatFlow_logs:
  729. folder = chatFlow_logs[difyId]['emails'] or []
  730. return emails
  731. def getDifyRecord_method(data):
  732. difyId = data.get('difyId')
  733. start_date = formateDate(data.get('startTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d')
  734. end_date = formateDate(data.get('endTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d')
  735. time_obj = {
  736. "startTime":formateDate(data.get('startTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d %H:%M'),
  737. "endTime":formateDate(data.get('endTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d %H:%M'),
  738. "startDate":start_date,
  739. "endDate":end_date,
  740. "is_same_day":is_same_day_str(start_date,end_date)
  741. }
  742. # now_time = formateDate(datetime.now(),"%a, %d %b %Y %H:%M:%S GMT",'%Y-%m-%d')
  743. time_str = start_date
  744. if not time_obj['is_same_day']:
  745. time_str = f'({start_date}-{end_date})'
  746. folder = getFilePath(difyId)
  747. file_name = f'{file_prefix}\{folder}\{time_str}-{folder}-使用情况.xlsx'
  748. time_obj['file_name'] = file_name
  749. file_path = os.path.join(os.getcwd(), '', file_name)
  750. if not os.path.exists(file_path):
  751. try:
  752. result = getDifyRecord1(data,time_obj)
  753. try:
  754. emails = getEmails(difyId)
  755. send_email(file_name,'请查收文件',[file_name],emails)
  756. except Exception as e:
  757. print(str(e))
  758. return jsonify(requestResponse.success(result))
  759. except HTTPError as http_err:
  760. return jsonify(requestResponse.any(http_err.response.status_code,'','token错误'))
  761. except Exception as e:
  762. print(e)
  763. return jsonify(requestResponse.error('error'))
  764. else:
  765. return jsonify(requestResponse.success(file_name))
  766. #获取当前显示版本数据
  767. @app.route(f'/api/getDifyRecord', methods=['POST'])
  768. async def getDifyRecord():
  769. data = request.get_json()
  770. return getDifyRecord_method(data)
  771. #下载文件
  772. @app.route(f'/api/download',methods=['GET'])
  773. async def download():
  774. get_params = request.args
  775. filename = get_params.get('filePath')
  776. file_path = os.path.join(os.getcwd(), '', filename)
  777. if not os.path.exists(file_path):
  778. abort(404) # 返回 404 错误
  779. try:
  780. # 返回文件给用户下载
  781. return send_file(file_path, as_attachment=True)
  782. except Exception as e:
  783. # 处理可能的异常(例如文件权限问题)
  784. return str(e), 500
  785. import smtplib
  786. from email.mime.text import MIMEText
  787. from email.mime.multipart import MIMEMultipart
  788. from email.mime.base import MIMEBase
  789. from email import encoders
  790. from email.header import Header
  791. from email.mime.application import MIMEApplication
  792. # 获取文件路径中的文件名称
  793. def getFileNameByFilePath(filePath):
  794. result = filePath.split('\\')
  795. if result and len(result)>0:
  796. return result[len(result)-1]
  797. else:
  798. return filePath
  799. def send_email(subject="使用情况", body='', attachments=None,emails=[]):
  800. sender="zhuliu@china-wispro.com"
  801. password="Xiaoshi221101"
  802. receiver="zl2780212168@163.com"
  803. if len(emails)>0:
  804. receiver = receiver + ', ' + ', '.join(emails)
  805. message = MIMEMultipart()
  806. message["From"] = sender
  807. message["To"] = receiver
  808. subject_str = getFileNameByFilePath(subject)
  809. message["Subject"] = Header(subject_str, "utf-8").encode()
  810. message.attach(MIMEText(body, "plain", "utf-8"))
  811. if attachments:
  812. for filename in attachments:
  813. with open(filename, "rb") as f:
  814. attachment = MIMEApplication(f.read())
  815. filename_str = getFileNameByFilePath(filename)
  816. attachment.add_header('Content-Disposition', 'attachment', filename=filename_str)
  817. message.attach(attachment)
  818. try:
  819. with smtplib.SMTP_SSL("smtp.exmail.qq.com", 465) as server:
  820. # server.starttls()
  821. server.login(sender, password)
  822. server.sendmail(sender, receiver, message.as_string())
  823. return True
  824. except Exception as e:
  825. print(f"Error: {e}")
  826. return False
  827. # MySQL数据库配置
  828. db_config = {
  829. 'host': '139.224.34.118',
  830. 'user': 'root',
  831. 'password': 'TU5x6IeBi7rl',
  832. 'db': 'PCS_PROD',
  833. 'charset': 'utf8mb4',
  834. 'cursorclass': pymysql.cursors.DictCursor,
  835. }
  836. db_config2 = {
  837. 'host': '139.224.34.118',
  838. 'user': 'root',
  839. 'password': 'TU5x6IeBi7rl',
  840. 'db': 'pas_prod2',
  841. 'charset': 'utf8mb4',
  842. 'cursorclass': pymysql.cursors.DictCursor,
  843. }
  844. # db_config2 = {
  845. # 'host': '192.168.2.24',
  846. # 'user': 'root',
  847. # 'password': 'rrzTwWAYX8Gxh5JH',
  848. # 'db': 'pas_prod2',
  849. # 'charset': 'utf8mb4',
  850. # 'cursorclass': pymysql.cursors.DictCursor,
  851. # }
  852. # 根据人员id获取部门
  853. def getDepartmentByPersonIds(ids):
  854. result = []
  855. if not ids:
  856. return result
  857. if len(ids) == 0:
  858. return result
  859. departmentList = []
  860. # 连接到数据库
  861. connection = pymysql.connect(**db_config)
  862. with connection.cursor() as cursor:
  863. query = f"SELECT a.PERSONNEL_ID as personId, b.* FROM ASSOCIATE_PERSONNEL_DP a left join ASSOCIATE_DEPARTMENT_POSITION b ON a.DEPARTMENT_AND_POSITION_ID = b.id where a.IS_DELETE != 1 and a.PERSONNEL_ID in ({','.join(ids)})"
  864. cursor.execute(query)
  865. results = cursor.fetchall()
  866. if results and len(results)>0:
  867. departmentIds = []
  868. for department in results:
  869. if 'DEPARTMENT_ID' in department:
  870. departmentIds.append(department['DEPARTMENT_ID'])
  871. query = f"SELECT * from DEPARTMENT where IS_DELETE != 1 && id in ({','.join(map(str,departmentIds))})"
  872. cursor.execute(query)
  873. departmentList = cursor.fetchall()
  874. if len(departmentList)>0:
  875. for person in results:
  876. departmentId = person['DEPARTMENT_ID']
  877. for department in departmentList:
  878. if departmentId == department['ID']:
  879. result.append(
  880. {
  881. 'personId':person['personId'],
  882. 'departmentId':departmentId,
  883. 'departmentName':department['DEPARTMENT_NAME']
  884. }
  885. )
  886. break
  887. connection.close()
  888. return result
  889. # 获取workflow的使用记录
  890. def getSession(data):
  891. start_date = formateDate(data.get('startTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d %H:%M')
  892. end_date = formateDate(data.get('endTime'),"%Y-%m-%dT%H:%M",'%Y-%m-%d %H:%M')
  893. type = data['type']
  894. result = []
  895. # 连接到数据库
  896. connection = pymysql.connect(**db_config2)
  897. with connection.cursor() as cursor:
  898. query = f'SELECT a.conversation_id,a.conversation_name,a.create_id as from_end_user_session_id,a.content,a.create_time as time,a.guid ,b.guid as resultGuid from confession_session a left join asso_confession_session_file b on a.id=b.confession_session_id where type = {type} and create_time >= "{start_date}" and create_time <= "{end_date}" order by create_time DESC'
  899. cursor.execute(query)
  900. results = cursor.fetchall()
  901. if results:
  902. # guids = [item['guid'] for item in results]
  903. guids = []
  904. resultGuids = []
  905. for item in results:
  906. if item['guid']:
  907. guids.append(item['guid'])
  908. if item['resultGuid']:
  909. resultGuids.append(item['resultGuid'])
  910. file_guid_obj = {}
  911. if len(guids)>0:
  912. guid_files = getFileMessageByGuid(guids)
  913. file_guid_obj = groupByField(guid_files,'guid')
  914. resultGuids_obj = {}
  915. if len(resultGuids)>0:
  916. resultGuids_files = getFileMessageByGuid(resultGuids)
  917. resultGuids_obj = groupByField(resultGuids_files,'guid')
  918. for item in results:
  919. guid = item['guid']
  920. guid_obj = {}
  921. if guid in file_guid_obj:
  922. file_data = file_guid_obj[guid]['data']
  923. if len(file_data):
  924. guid_obj = file_data[0]
  925. resultGuid = item['resultGuid']
  926. resultGuid_obj = {}
  927. if resultGuid in resultGuids_obj:
  928. resultGuid_data = resultGuids_obj[resultGuid]['data']
  929. if len(resultGuid_data):
  930. resultGuid_obj = resultGuid_data[0]
  931. obj = {
  932. "conversation_id":item['conversation_id'],
  933. "conversation_name":item['conversation_name'],
  934. "from_end_user_session_id":item['from_end_user_session_id'],
  935. "time":item['time'].strftime("%Y-%m-%d %H:%M:%S"),
  936. 'guid':guid,
  937. 'file':guid_obj,
  938. "input":"",
  939. "answer":"",
  940. 'resultFile':resultGuid_obj
  941. }
  942. if item['content']:
  943. try:
  944. contents = json.loads(item['content'])
  945. if 'query' in contents:
  946. obj['input'] = str(contents['query'])
  947. else:
  948. obj['input'] = ''
  949. if 'answer' in contents:
  950. obj['answer'] = str(contents['answer'])
  951. else:
  952. obj['answer'] = ''
  953. except Exception as e:
  954. print(e)
  955. result.append(obj)
  956. connection.close()
  957. return result
  958. #根据文件guid获取文件信息
  959. def getFileMessageByGuid(guids):
  960. if(not guids or len(guids) == 0):
  961. return []
  962. try:
  963. headers = {'Content-Type': 'application/json'}
  964. fileResponse = requests.post('https://xsip.cn/api/fileManager/getFileData', headers=headers, data=json.dumps(guids))
  965. fileResponse.raise_for_status()
  966. fileJson = fileResponse.json()
  967. return fileJson or []
  968. except Exception as e:
  969. return []
  970. if __name__ == '__main__':
  971. app.run(debug=True, host='0.0.0.0', port=3500)