newbot.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. import copy
  2. import fastapi
  3. import fastapi.staticfiles as fastapiStaticfiles
  4. import linebot
  5. import linebot.models as linebotModels
  6. import suggests
  7. from GoogleNews import GoogleNews
  8. import dataset
  9. import datetime
  10. from fastapi.responses import HTMLResponse
  11. #
  12. from linebot.models import (
  13. MessageEvent, TextMessage, TextSendMessage,
  14. SourceUser, SourceGroup, SourceRoom,
  15. TemplateSendMessage, ConfirmTemplate, MessageAction,
  16. ButtonsTemplate, ImageCarouselTemplate, ImageCarouselColumn, URIAction,
  17. PostbackAction, DatetimePickerAction,
  18. CameraAction, CameraRollAction, LocationAction,
  19. CarouselTemplate, CarouselColumn, PostbackEvent,
  20. StickerMessage, StickerSendMessage, LocationMessage, LocationSendMessage,
  21. ImageMessage, VideoMessage, AudioMessage, FileMessage,
  22. UnfollowEvent, FollowEvent, JoinEvent, LeaveEvent, BeaconEvent,
  23. MemberJoinedEvent, MemberLeftEvent,
  24. FlexSendMessage, BubbleContainer, ImageComponent, BoxComponent,
  25. TextComponent, IconComponent, ButtonComponent,
  26. SeparatorComponent, QuickReply, QuickReplyButton,
  27. ImageSendMessage)
  28. #uvicorn newbot:app --host 0.0.0.0 --port 5443 --ssl-keyfile=/etc/letsencrypt/live/api.ptt.cx/privkey.pem --ssl-certfile=/etc/letsencrypt/live/api.ptt.cx/fullchain.pem
  29. #uvicorn main:app --host 0.0.0.0 --port 443 --ssl-keyfile=/etc/letsencrypt/live/ptt.cx/privkey.pem --ssl-certfile=/etc/letsencrypt/live/ptt.cx/chain.pem
  30. #uvicorn main:app --host 0.0.0.0 --port 443 --key-file=/etc/letsencrypt/live/ptt.cx/privkey.pem --certfile=/etc/letsencrypt/live/ptt.cx/cert.pem
  31. # --keyfile=./key.pem --certfile=./cert.pem
  32. # --ssl-cert-reqs 1
  33. #
  34. # --ssl-ca-certs=/etc/letsencrypt/live/ptt.cx/fullchain.crt
  35. app = fastapi.FastAPI()
  36. #app.mount(
  37. # '/static', fastapiStaticfiles.StaticFiles(directory='static'), name='static')
  38. from linebot import (
  39. LineBotApi, WebhookHandler
  40. )
  41. from linebot.exceptions import (
  42. InvalidSignatureError
  43. )
  44. from linebot.models import (
  45. MessageEvent, TextMessage,ImageSendMessage, TextSendMessage,FlexSendMessage, TemplateSendMessage,CarouselTemplate,ConfirmTemplate,PostbackAction,MessageAction,CarouselColumn,URIAction
  46. )
  47. import json
  48. import codecs
  49. seo=False
  50. s_news=False
  51. line_bot_api = LineBotApi('Gub58t+8u9z7nTBrZLLvXnCbwDR1Gmyrew3nGFlKRxsmvH/oIMGjjup2DygA4XhV1NenM6dFTO8yvpbtCDezCqP2BAV4eVn2Y63/EYqeTCw1S+oJ+BiLLzC8DdVrWu9jSfp7wXqrVNUxcYdk54eoWAdB04t89/1O/w1cDnyilFU=')
  52. handler = WebhookHandler('f761bc6038c94a3baa815124e33dea50')
  53. #line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
  54. #handler = WebhookHandler('YOUR_CHANNEL_SECRET')
  55. def get_aws():
  56. result=''
  57. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/hhh?charset=utf8mb4')
  58. cursor=db.query('SELECT from_unixtime(eventtime) as dt,area FROM hhh.aws_monitor order by eventtime desc limit 4;')
  59. for c in cursor:
  60. result+=str(c['dt'])+"\n"+c['area']+"\n"
  61. return result
  62. def get_idea():
  63. result=''
  64. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/hhh?charset=utf8mb4')
  65. cursor=db.query('SELECT query FROM hhh.gsc_weekly where clicks > 500 order by rand() limit 10;')
  66. for c in cursor:
  67. result+=str(c['query'])+"\n"
  68. return result
  69. def get_hotkeys(past=False):
  70. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/yodb?charset=utf8mb4')
  71. now = ''
  72. sql_get_newest_data_date = 'SELECT * FROM trending_searches ORDER BY ts_date DESC'
  73. for row in db.query(sql_get_newest_data_date):
  74. now = row['ts_date']
  75. break
  76. if past:
  77. now =now-datetime.timedelta(days=1)
  78. now_start = now.strftime("%Y-%m-%d 00:00:00")
  79. now_end = now.strftime("%Y-%m-%d 23:59:59")
  80. sqls = 'SELECT * FROM trending_searches WHERE "'+now_end+'">= ts_date and "'+now_start+'"<=ts_date ORDER BY ts_date DESC'
  81. ls = []
  82. for row in db.query(sqls):
  83. ls.append(row['ts_word'])
  84. ls = list(dict.fromkeys(ls))
  85. return ls
  86. @app.get("/aws")
  87. async def aws():
  88. result='<html><head><link href="https://getbootstrap.com/docs/4.1/dist/css/bootstrap.min.css" rel="stylesheet"></head><body>'
  89. result+='製表時間: '+str(datetime.datetime.now())+'</br></br>\n\n'
  90. result+='<table class="table table-striped">'
  91. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/hhh?charset=utf8mb4')
  92. cursor=db.query('SELECT from_unixtime(eventtime) as dt,area FROM hhh.aws_monitor order by eventtime desc limit 30;')
  93. for c in cursor:
  94. result+="<tr><td>"+str(c['dt'])+"</td><td>"+c['area']+"</td></tr>\n"
  95. result+='</table></body></html>'
  96. return HTMLResponse(content=result, status_code=200)
  97. @app.get("/msg/{item_id}")
  98. async def coffee_msg(item_id):
  99. True
  100. line_bot_api.push_message(item_id, TextSendMessage(text='開啟下方完整券樣(密碼9888)至櫃台掃碼兌換。https://txp.rs/v/EvX69b4Xq9'))
  101. return {"code":"ok" }
  102. @app.post('/callback')
  103. async def callback(request: fastapi.Request):
  104. signature = request.headers['X-Line-Signature']
  105. body = await request.body()
  106. handler.handle(body.decode('utf-8'), signature)
  107. return 'OK'
  108. def get_news_by_kw(keyword):
  109. googlenews = GoogleNews(lang='zh-TW')
  110. kw=keyword
  111. googlenews.set_lang('zh-TW')
  112. googlenews.search(kw)
  113. resultstr="新聞:"
  114. idx=0
  115. rs=googlenews.results()
  116. for r in rs:
  117. if idx>0:
  118. resultstr+=','
  119. else:
  120. idx+=1
  121. resultstr+=r['title']
  122. return resultstr
  123. # print(r['desc'])
  124. # print(r['link'])
  125. # print(r['datetime'])
  126. def flex_test():
  127. js=json.load(open('test.json','r',encoding='utf-8'))
  128. for i in range(3):
  129. row_dict = {}
  130. row_dict['type'] = 'box'
  131. row_dict['layout'] = 'baseline'
  132. row_dict['contents']= [
  133. {
  134. "type": "text",
  135. "text": "第"+str(i)+"名",
  136. "size": "sm",
  137. "color": "#aaaaaa",
  138. "flex": 2
  139. },
  140. {
  141. "type": "text",
  142. "text": "hello, world"+str(1),
  143. "flex": 5,
  144. "weight": "regular"
  145. }
  146. ]
  147. js['body']['contents'] = js['body']['contents'] + [row_dict]
  148. return js
  149. @handler.add(FollowEvent)
  150. def handle_follow(event):
  151. print(event.source.user_id)
  152. # do something
  153. @handler.add(linebotModels.MessageEvent, message=linebotModels.TextMessage)
  154. def message_text(event):
  155. global seo
  156. global s_news
  157. ## if event.message.text == 'push':
  158. # line_bot_api.push_message(
  159. # event.source.user_id, [
  160. # # TextSendMessage(text='PUSH!'),
  161. # ]
  162. # )
  163. if event.message.text == 's_news':
  164. s_news=True
  165. line_bot_api.reply_message(
  166. event.reply_token,
  167. TextSendMessage(text='請輸入要搜尋新聞的關鍵字:'))
  168. return
  169. if event.message.text == 'q_aws':
  170. line_bot_api.reply_message(
  171. event.reply_token,[TextSendMessage(text=get_aws()),TextSendMessage(text='完整報告: https://api.ptt.cx:5443/aws')])
  172. return
  173. if event.message.text == 'q_idea':
  174. s_news=True
  175. line_bot_api.reply_message(
  176. event.reply_token,
  177. TextSendMessage(text=get_idea()))
  178. return
  179. ############################
  180. if event.message.text == 'hotkeys':
  181. line_bot_api.reply_message(
  182. event.reply_token,[TextSendMessage(text=get_aws()),TextSendMessage(text=get_hotkeys(False))])
  183. return
  184. if event.message.text == 'past_hotkeys':
  185. line_bot_api.reply_message(
  186. event.reply_token,[TextSendMessage(text=get_aws()),TextSendMessage(text=get_hotkeys(True))])
  187. return
  188. '''
  189. if event.message.text == 'seo':
  190. seo=True
  191. line_bot_api.reply_message(
  192. event.reply_token,
  193. TextSendMessage(text='請輸入要找的關鍵字:'))
  194. return
  195. '''
  196. if event.message.text=='js test':
  197. FlexMessage = flex_test()
  198. line_bot_api.reply_message(event.reply_token, FlexSendMessage('ChoozMo',FlexMessage))
  199. return
  200. if event.message.text=='熱門關鍵字':
  201. js=json.load(open('test.json','r',encoding='utf-8'))
  202. keys = get_hotkeys(past=False)
  203. num = 1
  204. for k in keys:
  205. row_dict = {}
  206. row_dict['type'] = 'box'
  207. row_dict['layout'] = 'baseline'
  208. row_dict['contents']= [
  209. {
  210. "type": "text",
  211. "text": "第"+str(num)+"名",
  212. "size": "sm",
  213. "color": "#aaaaaa",
  214. "flex": 2
  215. },
  216. {
  217. "type": "text",
  218. "text": k,
  219. "flex": 5,
  220. "weight": "regular"
  221. }
  222. ]
  223. num = num + 1
  224. js['body']['contents'] = js['body']['contents'] + [row_dict]
  225. line_bot_api.reply_message(event.reply_token, FlexSendMessage('ChoozMo',js))
  226. return
  227. if event.message.text=='關鍵字歷史走勢':
  228. js=json.load(open('test.json','r',encoding='utf-8'))
  229. keys = get_hotkeys(past=True)
  230. num = 1
  231. for k in keys:
  232. row_dict = {}
  233. row_dict['type'] = 'box'
  234. row_dict['layout'] = 'baseline'
  235. row_dict['contents']= [
  236. {
  237. "type": "text",
  238. "text": "第"+str(num)+"名",
  239. "size": "sm",
  240. "color": "#aaaaaa",
  241. "flex": 2
  242. },
  243. {
  244. "type": "text",
  245. "text": k,
  246. "flex": 5,
  247. "weight": "regular"
  248. }
  249. ]
  250. num = num + 1
  251. js['body']['contents'] = js['body']['contents'] + [row_dict]
  252. line_bot_api.reply_message(event.reply_token, FlexSendMessage('ChoozMo',js))
  253. return
  254. if event.message.text == '叫':
  255. line_bot_api.reply_message(
  256. event.reply_token, linebotModels.AudioSendMessage(
  257. original_content_url=f'{baseUrl}/static/audio/noot_noot.mp3', duration=1000))
  258. if event.message.text=='ok':
  259. line_bot_api.reply_message(
  260. event.reply_token,
  261. TextSendMessage(text='最欣賞ChoozMo團隊說OK的人!!'))
  262. if event.message.text=='c' or event.message.text=='C' :
  263. line_bot_api.reply_message(
  264. event.reply_token,
  265. TextSendMessage(
  266. text='快速鍵',
  267. quick_reply=QuickReply(
  268. items=[
  269. QuickReplyButton(
  270. action=MessageAction(label="熱門關鍵字", text="hotkeys")
  271. ),
  272. QuickReplyButton(
  273. action=MessageAction(label="關鍵字歷史走勢", text="past_hotkeys")
  274. ),
  275. #QuickReplyButton(
  276. # action=MessageAction(label="幸福空間靈感", text="q_idea")
  277. #),
  278. #QuickReplyButton(
  279. # action=MessageAction(label="查AWS", text="q_aws")
  280. #),
  281. #QuickReplyButton(
  282. # action=MessageAction(label="關聯字", text="seo")
  283. #),
  284. ])))
  285. else:
  286. if s_news:
  287. result=get_news_by_kw(event.message.text)
  288. line_bot_api.reply_message(
  289. event.reply_token,
  290. TextSendMessage(text=result))
  291. s_news=False
  292. return
  293. if seo:
  294. res='相關字:'
  295. s = suggests.suggests.get_suggests(event.message.text, source='google')
  296. idx=0
  297. for sg in s['suggests']:
  298. if idx>0:
  299. res+=','
  300. else:
  301. idx+=1
  302. res+=sg
  303. line_bot_api.reply_message(
  304. event.reply_token,
  305. TextSendMessage(text=res))
  306. seo=False
  307. # print('test')
  308. #if __name__ == "__main__":
  309. # app.run(host='0.0.0.0', port=443,ssl_context=('/etc/letsencrypt/live/ptt.cx/fullchain.pem', '/etc/letsencrypt/live/ptt.cx/privkey.pem'))
  310. # app.run(host='0.0.0.0', port=14404,ssl_context=('/tmp/cert.pem','/tmp/chain.pem' ))