CJYen 3 år sedan
förälder
incheckning
4a3b002421
50 ändrade filer med 1736 tillägg och 82 borttagningar
  1. 2 0
      .gitignore
  2. 0 9
      README.md
  3. 11 0
      api.py
  4. 0 73
      api/main.py
  5. 15 0
      apis/general_pages/route_homepage.py
  6. 1 0
      archived/docs/Untitled Diagram.drawio
  7. 4 0
      archived/docs/keyword.csv
  8. BIN
      archived/docs/output_file.utf16.csv
  9. 1 0
      archived/docs/s001.txt
  10. 68 0
      archived/docs/ta_test3.csv
  11. 4 0
      archived/docs/test.csv
  12. BIN
      archived/docs/test3.csv
  13. 68 0
      archived/docs/test3_2.csv
  14. 93 0
      archived/templates/base.html
  15. 67 0
      archived/templates/base2.html
  16. 251 0
      archived/templates/item.html
  17. 0 0
      archived/test/chart.html
  18. 15 0
      archived/test/heatmap1.py
  19. 16 0
      archived/test/heatmap2.py
  20. BIN
      archived/test/save_as_a_png.png
  21. 46 0
      archived/test/test.py
  22. 155 0
      archived/test/test2.py
  23. 20 0
      archived/test/test3.py
  24. 21 0
      archived/test/test4.py
  25. 16 0
      archived/test/treemap1.py
  26. 14 0
      archived/test/treemap2.py
  27. 17 0
      archived/test/treemap3.py
  28. 17 0
      archived/test/treemap4.py
  29. 24 0
      archived/test/treemap5.py
  30. 21 0
      archived/test/treemap6.py
  31. 75 0
      archived/test/treemap7.py
  32. 12 0
      archived/test/treemap8.py
  33. 12 0
      archived/test/treemap9.py
  34. 261 0
      archived/test/wordcloud1.py
  35. 7 0
      archived/test/wordcloud2.py
  36. 32 0
      archived/test/wordcloud3.py
  37. 20 0
      core/config.py
  38. 18 0
      db/session.py
  39. 124 0
      main.py
  40. 15 0
      requirements.txt
  41. BIN
      result/img.jpg
  42. BIN
      static/images/fastapi.png
  43. BIN
      static/images/logo.png
  44. 15 0
      static/styles.css
  45. 9 0
      static/styles.css.map
  46. 12 0
      static/styles.scss
  47. 36 0
      templates/components/navbar.html
  48. 93 0
      templates/general_pages/homepage.html
  49. BIN
      templates/general_pages/logo.png
  50. 28 0
      templates/shared/base.html

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+__pycache__
+.env

+ 0 - 9
README.md

@@ -1,9 +0,0 @@
-### Required
----
-- plotly
-- plotly_express
-- pandas
-
-### Result
----
-![result](./result/img.jpg)

+ 11 - 0
api.py

@@ -0,0 +1,11 @@
+from fastapi import APIRouter
+
+from app.api.api_v1.endpoints import login, users, nft, line, joyso, linepay
+
+api_router = APIRouter()
+api_router.include_router(login.router, tags=["login"])
+api_router.include_router(users.router, prefix="/user", tags=["user"])
+api_router.include_router(nft.router, prefix="/nft", tags=["nft"])
+api_router.include_router(line.router, prefix="/line", tags=["line"])
+api_router.include_router(joyso.router, prefix="/joyso", tags=["joyso"])
+api_router.include_router(linepay.router, prefix="/linepay", tags=["linepay"])

+ 0 - 73
api/main.py

@@ -1,73 +0,0 @@
-import pandas as pd
-from fastapi import FastAPI, File, UploadFile
-from fastapi.middleware.cors import CORSMiddleware
-import dataset
-from functools import reduce
-
-app = FastAPI()
-app.add_middleware(
-    CORSMiddleware,
-    allow_origins=['*'],
-    allow_credentials=True,
-    allow_methods=["*"],
-    allow_headers=["*"],
-)
-
-
-@app.post("/write/")
-async def writecsv(file: UploadFile = File(...)):
-    # read csv
-    repls = (' Stats ', '_'), (' at ', '_'), ('-', '_'), \
-            (' ', ''), ('.csv', '')
-    filename = file.filename
-    filename = reduce(lambda a, kv: a.replace(*kv), repls, filename)
-
-    data = file.file
-    df = pd.read_csv(data, sep=",",
-                     skiprows=0, na_values='NULL')
-
-    # db connect
-    db = dataset.connect(
-        'mysql://choozmo:pAssw0rd@db.ptt.cx:3306/keywordweb?charset=utf8mb4'
-    )
-
-    sql = "CREATE TABLE IF NOT EXISTS " \
-          + filename + \
-          "(ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, " \
-          "keyword VARCHAR(100), " \
-          "currency VARCHAR(100), avg_monthly_searches VARCHAR(100), " \
-          "three_month_change VARCHAR(100), " \
-          "yearly_change VARCHAR(100), competition VARCHAR(100), " \
-          "competition_indexed VARCHAR(100), " \
-          "top_page_bid_low_range VARCHAR(100), " \
-          "top_page_bid_hi_range VARCHAR(100)" \
-          ");"
-
-    db.query(sql)
-
-    # write to db
-    table = db[filename]
-    lines = df.shape
-    i = 0
-
-    rows = lines[0]
-
-    for i in range(rows):
-        row1 = df.iloc[i]
-        k = row1[0]
-        c = row1[1]
-        a = row1[2]
-        t = row1[3]
-        y = row1[4]
-        c1 = row1[5]
-        c2 = row1[6]
-        t1 = row1[7]
-        t2 = row1[8]
-
-        dbdata = dict(keyword=k, currency=c, avg_monthly_searches=a,
-                      three_month_change=t, yearly_change=y, competition=c1,
-                      competition_indexed=c2, top_page_bid_low_range=t1,
-                      top_page_bid_hi_range=t2)
-        table.insert(dbdata)
-
-    db.close()

+ 15 - 0
apis/general_pages/route_homepage.py

@@ -0,0 +1,15 @@
+from fastapi import APIRouter
+from fastapi import Request
+from fastapi.responses import HTMLResponse
+from fastapi.templating import Jinja2Templates
+
+templates = Jinja2Templates(directory="templates")
+general_pages_router = APIRouter()
+
+
+@general_pages_router.get("/")
+async def home(request: Request):
+    id = "測試"
+    return templates.TemplateResponse("general_pages/homepage.html", {"request": request, "id": id})
+
+

+ 1 - 0
archived/docs/Untitled Diagram.drawio

@@ -0,0 +1 @@
+<mxfile host="Electron" modified="2022-01-06T03:10:44.418Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.9.6 Chrome/89.0.4389.128 Electron/12.0.16 Safari/537.36" etag="NKVowr5RlOX15FK01CdN" version="14.9.6" type="device"><diagram id="fRxslVfQ8tQzlgJLsg4I" name="Page-1">3ZZRT8MgEMc/DY8mAzrHHm23qQ8mJtP4TNqzxdDSMLZ2fnqphXW1GjXRrPrU6/8OOH4cORCN8vpS8zK7UQlIRCZJjegCEYIpYfbTKPtWYWzSCqkWiQvqhLV4Bif6sK1IYNMLNEpJI8q+GKuigNj0NK61qvphj0r2Vy15CgNhHXM5VB9EYjK3CzLr9CsQaeZXxufz1pNzH+x2ssl4oqojiS4RjbRSprXyOgLZwPNc2nGrD7yHxDQU5isDVFCuSBDcGRWtdtf3vEp5fOZm2XG5dRtGyykKl4hFjcFWKPTpm71notW2SKCZFiMaVpkwsC553HgrWwVWy0wundstANpA/WHm+MDDFhKoHIze2xA3gJy7HFwN+d+qOxDsKWdHh+HjuKuB9DBzh8kajtQ3qJF3qAUoZIhdvFIjKKSjo4anp8ZG3y22iwWas0U4Ol4kODWvYMCLl+LknAIcjOs2TgeYnjaqGB2n09+/2RBUZQacbJ8qG9PulEsJUqWa5xZJCVrYPEC/9d12js+wPooafJP/IcwYj6w5sAHleLP785QnY2sm/tiPOCud/zfOv9mE7G/3+nz1Hb3h6fIF</diagram></mxfile>

+ 4 - 0
archived/docs/keyword.csv

@@ -0,0 +1,4 @@
+Keyword,Currency,Avg,bid
+剪輯,TWD,5000%,0
+素材,TWD,50000%,1
+影片製作,TWD,5000%,2

BIN
archived/docs/output_file.utf16.csv


+ 1 - 0
archived/docs/s001.txt

@@ -0,0 +1 @@
+This is test upload

+ 68 - 0
archived/docs/ta_test3.csv

@@ -0,0 +1,68 @@
+Keyword Stats 2022-01-04 at 10_37_23
+2020年12月1日 - 2021年11月30日
+Keyword	Currency	Avg. monthly searches	三個月內的變化	逐年變化	Competition	Competition (indexed value)	Top of page bid (low range)	Top of page bid (high range)	Ad impression share	Organic impression share	Organic average position	In account?	In plan?	Searches: Dec 2020	Searches: Jan 2021	Searches: Feb 2021	Searches: Mar 2021	Searches: Apr 2021	Searches: May 2021	Searches: Jun 2021	Searches: Jul 2021	Searches: Aug 2021	Searches: Sep 2021	Searches: Oct 2021	Searches: Nov 2021	Concept: 非品牌
+舊 倉庫	TWD	50	0%	0%	低	0																				
+南港 活動	TWD	500	900%	0%	低	5	4.62	12.12																		
+livehouse	TWD	5000	0%	0%	低	1	7.13	60.81																		
+工業 辦公室	TWD	50	0%	0%	高	86																				
+多 功能 空間	TWD	50	0%	900%	中	42	12.00	27.08																		
+歷史 建築	TWD	500	-90%	-90%	低	0																				
+快 閃 活動	TWD	500	0%	0%	低	3																				
+演唱 會	TWD	50000	900%	0%	低	10	6.28	10.83																		
+講座	TWD	5000	0%	0%	低	6	10.58	28.77																		
+南港 展覽 館 活動	TWD	500	900%	0%	低	5	5.50	14.91																		Non-Brands
+南港 展覽 館 2 館 活動	TWD	500	900%	0%	低	8	4.90	9.30																		Non-Brands
+南港 展覽 館 2 館 近期 活動	TWD	500	0%	0%	低	7	5.80	12.68																		Non-Brands
+lau bak livehouse	TWD	50	0%	0%	不明																					Non-Brands
+南港 展覽 館 1 館 活動	TWD	50	900%	0%	低	3	5.00	14.91																		Non-Brands
+2021 南港 展覽 館	TWD	50	900%	∞	低	9	4.83	13.00																		Non-Brands
+南港 展覽 2 館	TWD	50	900%	900%	低	3	4.33	7.04																		Non-Brands
+南港 展覽 館 2021	TWD	50	0%	∞	低	12	6.36	12.57																		Non-Brands
+南港 展覽 館 4 樓	TWD	50	0%	-90%	低	1																				Non-Brands
+南港 展覽 2021	TWD	50	900%	∞	低	12	6.34	13.15																		Non-Brands
+南港 展覽 館 門票	TWD	50	900%	900%	低	5	2.74	8.56																		Non-Brands
+ez live house	TWD	50	0%	0%	低	0																				Non-Brands
+南港 展覽 館 官方 網站	TWD	50	0%	0%	低	0																				Non-Brands
+南港 展覽 館 場地 租借	TWD	50	0%	0%	中	34	6.39	20.88																		Non-Brands
+南港 展覽 館 租借	TWD	50	0%	0%	低	13	5.95	17.93																		Non-Brands
+南港 展覽 館 展覽 時間	TWD	50	900%	900%	低	7	5.44	11.74																		Non-Brands
+lost stars livehouse bar & eatery 近期 活動	TWD	50	0%	0%	不明																					Non-Brands
+南港 展覽 館 智慧 城市	TWD	50	0%	0%	不明																					Non-Brands
+南港 二 館 展覽	TWD	50	0%	0%	低	10	4.65	12.52																		Non-Brands
+南港 展覽 館 食品 展 門票	TWD	50	∞	0%	低	32	4.53	12.68																		Non-Brands
+南港 展覽 館 智慧 城市 展	TWD	50	-100%	0%	不明																					Non-Brands
+南港 展覽 館 二 館 展覽	TWD	50	0%	0%	低	11	4.27	6.63																		Non-Brands
+南港 展覽 館 演唱 會 2021	TWD	50	0%	∞	低	9																				Non-Brands
+南港 展覽 館 11 月	TWD	50	0%	0%	低	7	6.51	13.77																		Non-Brands
+南港 展覽 館 一 館 平面圖	TWD	50	900%	900%	低	0																				Non-Brands
+南港 展覽 館 j 區	TWD	50	900%	900%	低	1																				Non-Brands
+南港 展覽 館 展覽 活動	TWD	50	0%	0%	低	19																				Non-Brands
+南港 展覽 館 攤位	TWD	50	0%	0%	低	5																				Non-Brands
+南港 展覽 館 今日 活動	TWD	50	0%	0%	低	25	5.47	12.68																		Non-Brands
+南港 展覽 館 近期 活動	TWD	50	0%	0%	低	7	5.44	12.32																		Non-Brands
+thewall livehouse	TWD		 --	 --	不明																					Non-Brands
+南港 展覽 館 烘焙 展 時間	TWD	50	0%	0%	不明																					Non-Brands
+週末 講座	TWD	50	0%	0%	高	86																				Non-Brands
+南港 展覽 館 12 月 活動	TWD	50	∞	0%	低	21	8.34	14.52																		Non-Brands
+南港 展覽 館 四 樓	TWD	50	0%	0%	低	2																				Non-Brands
+南港 展覽 館 展覽 資訊	TWD	50	900%	900%	低	19	4.66	11.48																		Non-Brands
+南港 展覽 館 10 月	TWD	50	0%	0%	低	5																				Non-Brands
+南港 展覽 館 場地	TWD	50	0%	0%	低	8																				Non-Brands
+南港 展覽 館 現在 展 什麼	TWD	50	∞	0%	低	24																				Non-Brands
+聖 雅 各 福 群 會 講座	TWD	0	0%	0%	不明																					Non-Brands
+南港 展覽 館 國際 食品 展	TWD	50	∞	0%	低	0																				Non-Brands
+南港 展覽 館 雲端 展 場	TWD	50	∞	0%	低	3																				Non-Brands
+南港 展覽 館 露營 展	TWD	50	∞	0%	低	13	1.96	4.32																		Non-Brands
+南港 展覽 館 要 門票 嗎	TWD	50	0%	0%	低	2																				Non-Brands
+南港 展覽 2020	TWD	50	0%	-100%	不明																					Non-Brands
+ez5livehouse	TWD		 --	 --	不明																					Non-Brands
+南港 展覽 館 農業 展	TWD	50	∞	0%	低	12																				Non-Brands
+南港 展覽 館 有 什麼 活動	TWD	50	0%	0%	低	23	4.46	12.15																		Non-Brands
+南港 展覽 區	TWD	50	0%	0%	低	14																				Non-Brands
+11 月 南港 展覽 館	TWD	50	0%	0%	低	19	3.60	7.53																		Non-Brands
+南港 展覽 館 今天 活動	TWD	50	∞	0%	低	25																				Non-Brands
+南港 第 二 展覽 館	TWD	50	∞	0%	低	8																				Non-Brands
+南港 展覽 館 11 1	TWD	50	0%	-100%	不明																					Non-Brands
+南港 展覽 館 4 月	TWD	50	0%	0%	不明																					Non-Brands
+南港 展覽 館 貓	TWD	50	∞	0%	低	14																				Non-Brands
+南港 展覽 館 售票	TWD	50	∞	0%	低	2																				Non-Brands

+ 4 - 0
archived/docs/test.csv

@@ -0,0 +1,4 @@
+Keyword,Currency,Avg monthly searches,三個月內的變化,逐年變化,Competition,Competition (indexed value),Top of page bid (low range),Top of page bid (high range)
+ark,TWD,50000,0%,0%,低,7,405,6463
+元 宇宙,TWD,50000,900%,∞,低,3,019,039
+主題 館,TWD,500,0%,0%,低,0, 2, 3

BIN
archived/docs/test3.csv


+ 68 - 0
archived/docs/test3_2.csv

@@ -0,0 +1,68 @@
+Keyword Stats 2022-01-04 at 10_37_23
+2020年12月1日 - 2021年11月30日
+Keyword	Currency	Avg. monthly searches	三個月內的變化	逐年變化	Competition	Competition (indexed value)	Top of page bid (low range)	Top of page bid (high range)	Ad impression share	Organic impression share	Organic average position	In account?	In plan?	Searches: Dec 2020	Searches: Jan 2021	Searches: Feb 2021	Searches: Mar 2021	Searches: Apr 2021	Searches: May 2021	Searches: Jun 2021	Searches: Jul 2021	Searches: Aug 2021	Searches: Sep 2021	Searches: Oct 2021	Searches: Nov 2021	Concept: 非品牌
+舊 倉庫	TWD	50	0%	0%	低	0																				
+南港 活動	TWD	500	900%	0%	低	5	4.62	12.12																		
+livehouse	TWD	5000	0%	0%	低	1	7.13	60.81																		
+工業 辦公室	TWD	50	0%	0%	高	86																				
+多 功能 空間	TWD	50	0%	900%	中	42	12.00	27.08																		
+歷史 建築	TWD	500	-90%	-90%	低	0																				
+快 閃 活動	TWD	500	0%	0%	低	3																				
+演唱 會	TWD	50000	900%	0%	低	10	6.28	10.83																		
+講座	TWD	5000	0%	0%	低	6	10.58	28.77																		
+南港 展覽 館 活動	TWD	500	900%	0%	低	5	5.50	14.91																		Non-Brands
+南港 展覽 館 2 館 活動	TWD	500	900%	0%	低	8	4.90	9.30																		Non-Brands
+南港 展覽 館 2 館 近期 活動	TWD	500	0%	0%	低	7	5.80	12.68																		Non-Brands
+lau bak livehouse	TWD	50	0%	0%	不明																					Non-Brands
+南港 展覽 館 1 館 活動	TWD	50	900%	0%	低	3	5.00	14.91																		Non-Brands
+2021 南港 展覽 館	TWD	50	900%	∞	低	9	4.83	13.00																		Non-Brands
+南港 展覽 2 館	TWD	50	900%	900%	低	3	4.33	7.04																		Non-Brands
+南港 展覽 館 2021	TWD	50	0%	∞	低	12	6.36	12.57																		Non-Brands
+南港 展覽 館 4 樓	TWD	50	0%	-90%	低	1																				Non-Brands
+南港 展覽 2021	TWD	50	900%	∞	低	12	6.34	13.15																		Non-Brands
+南港 展覽 館 門票	TWD	50	900%	900%	低	5	2.74	8.56																		Non-Brands
+ez live house	TWD	50	0%	0%	低	0																				Non-Brands
+南港 展覽 館 官方 網站	TWD	50	0%	0%	低	0																				Non-Brands
+南港 展覽 館 場地 租借	TWD	50	0%	0%	中	34	6.39	20.88																		Non-Brands
+南港 展覽 館 租借	TWD	50	0%	0%	低	13	5.95	17.93																		Non-Brands
+南港 展覽 館 展覽 時間	TWD	50	900%	900%	低	7	5.44	11.74																		Non-Brands
+lost stars livehouse bar & eatery 近期 活動	TWD	50	0%	0%	不明																					Non-Brands
+南港 展覽 館 智慧 城市	TWD	50	0%	0%	不明																					Non-Brands
+南港 二 館 展覽	TWD	50	0%	0%	低	10	4.65	12.52																		Non-Brands
+南港 展覽 館 食品 展 門票	TWD	50	∞	0%	低	32	4.53	12.68																		Non-Brands
+南港 展覽 館 智慧 城市 展	TWD	50	-100%	0%	不明																					Non-Brands
+南港 展覽 館 二 館 展覽	TWD	50	0%	0%	低	11	4.27	6.63																		Non-Brands
+南港 展覽 館 演唱 會 2021	TWD	50	0%	∞	低	9																				Non-Brands
+南港 展覽 館 11 月	TWD	50	0%	0%	低	7	6.51	13.77																		Non-Brands
+南港 展覽 館 一 館 平面圖	TWD	50	900%	900%	低	0																				Non-Brands
+南港 展覽 館 j 區	TWD	50	900%	900%	低	1																				Non-Brands
+南港 展覽 館 展覽 活動	TWD	50	0%	0%	低	19																				Non-Brands
+南港 展覽 館 攤位	TWD	50	0%	0%	低	5																				Non-Brands
+南港 展覽 館 今日 活動	TWD	50	0%	0%	低	25	5.47	12.68																		Non-Brands
+南港 展覽 館 近期 活動	TWD	50	0%	0%	低	7	5.44	12.32																		Non-Brands
+thewall livehouse	TWD		 --	 --	不明																					Non-Brands
+南港 展覽 館 烘焙 展 時間	TWD	50	0%	0%	不明																					Non-Brands
+週末 講座	TWD	50	0%	0%	高	86																				Non-Brands
+南港 展覽 館 12 月 活動	TWD	50	∞	0%	低	21	8.34	14.52																		Non-Brands
+南港 展覽 館 四 樓	TWD	50	0%	0%	低	2																				Non-Brands
+南港 展覽 館 展覽 資訊	TWD	50	900%	900%	低	19	4.66	11.48																		Non-Brands
+南港 展覽 館 10 月	TWD	50	0%	0%	低	5																				Non-Brands
+南港 展覽 館 場地	TWD	50	0%	0%	低	8																				Non-Brands
+南港 展覽 館 現在 展 什麼	TWD	50	∞	0%	低	24																				Non-Brands
+聖 雅 各 福 群 會 講座	TWD	0	0%	0%	不明																					Non-Brands
+南港 展覽 館 國際 食品 展	TWD	50	∞	0%	低	0																				Non-Brands
+南港 展覽 館 雲端 展 場	TWD	50	∞	0%	低	3																				Non-Brands
+南港 展覽 館 露營 展	TWD	50	∞	0%	低	13	1.96	4.32																		Non-Brands
+南港 展覽 館 要 門票 嗎	TWD	50	0%	0%	低	2																				Non-Brands
+南港 展覽 2020	TWD	50	0%	-100%	不明																					Non-Brands
+ez5livehouse	TWD		 --	 --	不明																					Non-Brands
+南港 展覽 館 農業 展	TWD	50	∞	0%	低	12																				Non-Brands
+南港 展覽 館 有 什麼 活動	TWD	50	0%	0%	低	23	4.46	12.15																		Non-Brands
+南港 展覽 區	TWD	50	0%	0%	低	14																				Non-Brands
+11 月 南港 展覽 館	TWD	50	0%	0%	低	19	3.60	7.53																		Non-Brands
+南港 展覽 館 今天 活動	TWD	50	∞	0%	低	25																				Non-Brands
+南港 第 二 展覽 館	TWD	50	∞	0%	低	8																				Non-Brands
+南港 展覽 館 11 1	TWD	50	0%	-100%	不明																					Non-Brands
+南港 展覽 館 4 月	TWD	50	0%	0%	不明																					Non-Brands
+南港 展覽 館 貓	TWD	50	∞	0%	低	14																				Non-Brands
+南港 展覽 館 售票	TWD	50	∞	0%	低	2																				Non-Brands

+ 93 - 0
archived/templates/base.html

@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html lang="zh-TW">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1" />
+
+  <!-- 提供 ico 檔案 -->
+  <link rel="icon" href="{{ url_for('static', filename='img/alpaca_logo.ico') }}">
+
+  <!-- 引入 cdn CSS -->
+  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+TC&display=swap">
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.css">  
+
+  <!-- 引入我們自己的 CSS -->
+  <link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}">
+
+  <!-- 直接定義 CSS -->
+  <style> body {font-family: 'Noto Sans TC', sans-serif;}</style>
+
+  <!-- 可供更改的部分 -->
+  <title>{% block title %}{% endblock %}</title>
+
+</head>
+
+<body>
+  <nav class="navbar navbar-expand navbar-dark bg-dirty-purple">
+  <a class="navbar-brand" href="/">賴田捕手</a>
+  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+    <span class="navbar-toggler-icon"></span>
+  </button>
+
+  <div class="collapse navbar-collapse" id="navbarSupportedContent">
+    <ul class="navbar-nav mr-auto">
+      <li class="nav-item">
+        <a class="nav-link" href="/from_start">從頭開始</span></a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#">LINE-Bot-Sdk</a>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link" href="#">Heroku Postgres</a>
+      </li>
+      <li class="nav-item dropdown">
+        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+          Flask
+        </a>
+        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
+          <a class="dropdown-item" href="#">基本架構</a>
+          <a class="dropdown-item" href="#">網頁設計</a>
+          <div class="dropdown-divider"></div>
+          <a class="dropdown-item" href="#">接下來的</a>
+        </div>
+      </li>
+      <li class="nav-item">
+        <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">施工中</a>
+      </li>
+    </ul>
+  <ul class="navbar-nav ml-auto">
+    <li class="nav-item">
+        <a class="nav-link" href="#">請靠右走</a>
+      </li>
+  </ul>
+  </div>
+  </nav>
+
+  <main>
+    {% block main %}{% endblock %}
+  </main>
+
+<footer class="bg-light">
+  <div class="container-fluid">
+    <div class="row">
+    <div class="col">
+  <ul class="list-group list-group-horizontal">
+  <li class="list-group-item bg-light border-light"><a href="https://ithelp.ithome.com.tw/users/20120178/ironman/2654">iT邦幫忙鐵人賽</a></li>
+    <li class="list-group-item bg-light border-light"><a href="https://github.com/githubmhjao">Github</a></li>
+      </ul></div>
+      <div class="col">
+      <ul class="list-group list-group-horizontal">
+        <li class="list-group-item bg-light border-light">當前網站採用 Bootstrap v4.3.1 版本, <a href="https://github.com/twbs/bootstrap/blob/master/LICENSE" target="_blank" rel="license noopener">MIT</a>, docs <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank" rel="license noopener">CC BY 3.0</a>.</li>
+      </ul>
+      </div>
+  </div>
+</footer>
+
+  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
+  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
+
+  {% block script %}{% endblock %}
+</body>
+</html>

+ 67 - 0
archived/templates/base2.html

@@ -0,0 +1,67 @@
+<script>
+  var ctx10 = document.getElementById('bar-yt');
+  var myChart10 = new Chart(ctx10, {
+    type: 'bar', //圖表類型
+    data: {
+      //標題
+      labels: [ "{{ keyword }}", '那些足球教我的事'],
+      datasets: [
+        {
+          label: '月搜量',
+          data: [50, 11],
+          borderColor: 'rgba(255, 206, 86, 1)',
+          backgroundColor: 'rgba(255, 206, 86, 1)',
+        },
+        {
+          label: '金額',
+          data: [40.57, 91.72],
+          borderColor: 'rgba(255, 99, 132, 1)',
+          backgroundColor: 'rgba(255, 99, 132, 1)',
+        },
+      ],
+    },
+    options: {
+      // indexAxis: 'y',
+      plugins: {
+        legend: {
+          // display: false,
+          labels: {
+            padding: 5,
+            font: {
+              display: false,
+              size: 16,
+            },
+          },
+        },
+      },
+      scales: {
+        x: {
+          ticks: {
+            font: {
+              size: 16,
+            }
+          },
+          title: {
+            display: false,
+            font: {
+              family: 'Times',
+              size: 48,
+            },
+          },
+        },
+        y: {
+          title: {
+            display: true,
+          },
+          ticks: {
+            font: {
+              size: 16,
+            }
+          },
+          beginAtZero: true,
+        }
+      }
+    }
+  });
+</script>
+

+ 251 - 0
archived/templates/item.html

@@ -0,0 +1,251 @@
+<html>
+  
+<head>
+    <title>Item Details</title>
+    <link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
+    <!-- Chart.js v2.4.0 -->
+	<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
+</head>
+<body>
+    <img src="{{ url_for('static', path='/fastapi.png') }}" alt="FastAPI">
+    <h1>Item ID: {{ id }}</h1>
+    <h1>Title: {{ titles }}</h1>
+    <canvas id="bar-yt" width="400" height="200"></canvas>
+    <canvas id="myChart-pie" width="400" height="200"></canvas>
+    <canvas id="bar-yt1" width="400" height="200"></canvas>  
+    
+    <p>
+      接著
+    </p>
+    
+    <script>
+      var ctx10 = document.getElementById('bar-yt');
+      var myChart10 = new Chart(ctx10, {
+        type: 'bar', //圖表類型
+        data: {
+          //標題
+          labels: [ "那些足球教我的事", '那些足球教我的事'],
+          datasets: [
+            {
+              label: '月搜量',
+              data: [50, 11],
+              borderColor: 'rgba(255, 206, 86, 1)',
+              backgroundColor: 'rgba(255, 206, 86, 1)',
+            },
+            {
+              label: '金額',
+              data: [40.57, 91.72],
+              borderColor: 'rgba(255, 99, 132, 1)',
+              backgroundColor: 'rgba(255, 99, 132, 1)',
+            },
+          ],
+        },
+        options: {
+          // indexAxis: 'y',
+          plugins: {
+            legend: {
+              // display: false,
+              labels: {
+                padding: 5,
+                font: {
+                  display: false,
+                  size: 16,
+                },
+              },
+            },
+          },
+          scales: {
+            x: {
+              ticks: {
+                font: {
+                  size: 16,
+                }
+              },
+              title: {
+                display: false,
+                font: {
+                  family: 'Times',
+                  size: 48,
+                },
+              },
+            },
+            y: {
+              title: {
+                display: true,
+              },
+              ticks: {
+                font: {
+                  size: 16,
+                }
+              },
+              beginAtZero: true,
+            }
+          }
+        }
+      });
+    </script>
+    <h1>id: {{ id }}</h1>
+    
+    <script>
+    var ctx10 = document.getElementById('bar-yt');
+    var myChart10 = new Chart(ctx10, {
+      type: 'bar', //圖表類型
+      data: {
+        //標題
+        labels: [ "{{ keyword }}", '那些足球教我的事'],
+        datasets: [
+          {
+            label: '月搜量',
+            data: [50, 11],
+            borderColor: 'rgba(255, 206, 86, 1)',
+            backgroundColor: 'rgba(255, 206, 86, 1)',
+          },
+          {
+            label: '金額',
+            data: [40.57, 91.72],
+            borderColor: 'rgba(255, 99, 132, 1)',
+            backgroundColor: 'rgba(255, 99, 132, 1)',
+          },
+        ],
+      },
+      options: {
+        // indexAxis: 'y',
+        plugins: {
+          legend: {
+            // display: false,
+            labels: {
+              padding: 5,
+              font: {
+                display: false,
+                size: 16,
+              },
+            },
+          },
+        },
+        scales: {
+          x: {
+            ticks: {
+              font: {
+                size: 16,
+              }
+            },
+            title: {
+              display: false,
+              font: {
+                family: 'Times',
+                size: 48,
+              },
+            },
+          },
+          y: {
+            title: {
+              display: true,
+            },
+            ticks: {
+              font: {
+                size: 16,
+              }
+            },
+            beginAtZero: true,
+          }
+        }
+      }
+    });
+    </script>
+
+
+{% block script %}{% endblock %}
+
+
+    <script>
+    var ctx10 = document.getElementById('bar-yt1');
+    var myChart11 = new Chart(ctx10, {
+      type: 'bar', //圖表類型
+      data: {
+        //標題
+        labels: [ "{{ keyword }}", '那些足球教我的事'],
+        datasets: [
+          {
+            label: '月搜量',
+            data: [50, 11],
+            borderColor: 'rgba(255, 206, 86, 1)',
+            backgroundColor: 'rgba(255, 206, 86, 1)',
+          },
+          {
+            label: '金額',
+            data: [40.57, 91.72],
+            borderColor: 'rgba(255, 99, 132, 1)',
+            backgroundColor: 'rgba(255, 99, 132, 1)',
+          },
+        ],
+      },
+      options: {
+        // indexAxis: 'y',
+        plugins: {
+          legend: {
+            // display: false,
+            labels: {
+              padding: 5,
+              font: {
+                display: false,
+                size: 16,
+              },
+            },
+          },
+        },
+        scales: {
+          x: {
+            ticks: {
+              font: {
+                size: 16,
+              }
+            },
+            title: {
+              display: false,
+              font: {
+                family: 'Times',
+                size: 48,
+              },
+            },
+          },
+          y: {
+            title: {
+              display: true,
+            },
+            ticks: {
+              font: {
+                size: 16,
+              }
+            },
+            beginAtZero: true,
+          }
+        }
+      }
+    });
+    </script>
+
+
+	<!-- <script>
+		var ctx = document.getElementById( "example" ),
+		example = new Chart(ctx, {
+				// 參數設定[註1]
+				type: "bar", // 圖表類型
+				data: {
+					// 資料設定[註2]
+					labels: [ "{{ id }}", "{{ id }}", "{{ id }}" ], // 標題
+					datasets: [{
+						// 資料參數設定[註3]
+						label: "# of Votes", // 標籤
+						data: [ {{ id }}, {{ num }}, {{ num }} ], // 資料
+						backgroundColor: [ // 背景色
+						"#FF0000",
+						"#00FF00",
+						"#0000FF",
+						],
+						borderWidth: 1 // 外框寬度
+					}]
+				}
+			});
+	</script> -->
+</body>
+</html>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
archived/test/chart.html


+ 15 - 0
archived/test/heatmap1.py

@@ -0,0 +1,15 @@
+import numpy as np
+import matplotlib.pyplot as plt
+import seaborn as sns
+from PIL import Image
+
+# %config InlineBackend.figure_format = 'retina' # for using juyter hi-res render
+
+# 設定隨機種子
+np.random.seed(0)
+
+# 從均勻分配(0~1)之間抽出2*3陣列
+uniform_data = np.random.rand(2, 3)
+r = sns.heatmap(uniform_data)
+# sns.plt.show()
+r.savefig("y.jpg")

+ 16 - 0
archived/test/heatmap2.py

@@ -0,0 +1,16 @@
+import pandas as pd
+import matplotlib.pyplot as plt
+import seaborn as sns
+
+df = pd.DataFrame({"Day 1": [4,1,3],
+                    "Day 2" : [1,2,4],
+                    "Day 3" : [2,1,3]})
+
+# sns.heatmap(df.corr())
+sns.heatmap(df.corr(), vmin = -1, vmax = +1, annot = True, cmap = 'coolwarm')
+
+# sns.lineplot(data = df)
+path = '../img/'
+filename = 'filename.png'
+saved = path + filename
+plt.savefig(saved, dpi = 300)

BIN
archived/test/save_as_a_png.png


+ 46 - 0
archived/test/test.py

@@ -0,0 +1,46 @@
+import pandas as pd
+
+
+def conv(file):
+  ff_name = file
+  target_file_name = "ta_"+ff_name
+  with open(ff_name, 'rb') as source_file:
+    with open(target_file_name, 'w+b') as dest_file:
+      contents = source_file.read()
+      dest_file.write(contents.decode('utf-16').encode('utf-8'))
+  # data = "../docs/test3.csv"
+  data = target_file_name
+  df = pd.read_csv(data, sep="\t", skiprows=2)  # 制表符分隔tab
+  # df = pd.read_csv(data, skiprows=2)  # 制表符分隔tab
+  return df
+
+conv("test3.csv")
+# df = pd.read_csv(data2, sep=",", skiprows=0, keep_default_na=False, na_values='NULL')  # 制表符分隔tab
+# filename = "test"
+#
+# keywords = df.iloc[0]
+# keyword1 = df['Keyword']
+# # print("keyword: ", keywords)
+# # print("keyword: ", keyword1)
+# lines = df.shape
+# i = 0
+
+
+# rows = lines[0]
+# db = dataset.connect('mysql://root:pAssw0rd@localhost:3306/keyword?charset=utf8mb4')
+# table = db[filename]
+# # print(table)
+# # for i in range(rows):
+# #     row1 = df.iloc[i]
+# #     k = df['Keyword']
+# #     c = df['Currency']
+# #     a = df['Avg monthly searches']
+# #     # table.insert(dict(Keyword=k, Currency=c, AvgMonthlySearches=a))
+# #     print("row: ", row1)
+# #     print("k: ", k)
+# #     print("c: ", c)
+# #
+# #     i += 1
+# k = df['Keyword']
+# print("k: ", k)
+# db.close()

+ 155 - 0
archived/test/test2.py

@@ -0,0 +1,155 @@
+import pandas as pd
+from fastapi import FastAPI, File, Form, UploadFile, Response, Request, Depends, BackgroundTasks
+from fastapi.middleware.cors import CORSMiddleware
+from fastapi.responses import HTMLResponse, FileResponse
+import dataset
+from fastapi.templating import Jinja2Templates
+from fastapi.staticfiles import StaticFiles
+import uvicorn
+from typing import List
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+import time
+import shutil
+import logging
+import traceback
+import aiofiles
+
+app = FastAPI()
+app.add_middleware(
+    CORSMiddleware,
+    allow_origins=['*'],
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+
+resource_server = 'www.keyword.web:8000/'
+tmp_csv_sub_folder = 'tmp_csv/'
+img_upload_folder = '/var/www/html/'+tmp_csv_sub_folder
+
+app.mount("../static", StaticFiles(directory="static"), name="static")
+# templates = Jinja2Templates(directory="../html")
+templates = Jinja2Templates(directory="../templates/")
+oauth_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+@app.get("/user/{id}", response_class=HTMLResponse)
+def home(request: Request, id:str):
+    name = "cat"
+    return templates.TemplateResponse("home.html", {"request": request, "name": name, "id": id})
+
+
+@app.get("/index_eng", response_class=HTMLResponse)
+async def index2():
+    return FileResponse('../html/index_eng.html')
+
+@app.post("/root0")
+async def root0(file: UploadFile = File(...)):
+    with open(f'{file.filename}', "wb") as buffer:
+        shutil.copyfileobj(file.file, buffer)
+    return {"file_name": file.filename}
+
+
+@app.post("/csv")
+async def csv(files: List[UploadFile] = File(...)):
+    lists = {}
+    i = 0
+    for csv in files:
+        with open(f'{csv.filename}', "wb") as buffer:
+            shutil.copyfileobj(csv.file, buffer)
+        lists[i] = csv.filename
+        i += 1
+    return {"files uploaded": lists}
+
+
+@app.post('/upfile1')
+async def up_f1(request:Request,upload_list:List[UploadFile]= File(...)):
+    return templates.TemplateResponse(
+        'f.html',
+        {
+            "request":request,
+            "file_names":[dd.filename for dd in upload_list],
+            "file_sizes":[len(ds.read())/1024 for ds in [dd.file for dd in upload_list]],
+            "file_types":[dd.content_type for dd in upload_list]
+        })
+
+
+
+def handle_email_background(email: str, data: str):
+    print(email)
+    print(data)
+    for i in range(100):
+        print(i)
+        time.sleep(0.1)
+
+
+@app.get("/users/email")
+async def handle_email(email: str, background_task:BackgroundTasks):
+    print(email)
+    background_task.add_task(handle_email_background, email, "This is background task")
+    return {"message": "mail sent"}
+
+
+@app.post("/token")
+async def token_generate(form_data: OAuth2PasswordRequestForm = Depends()):
+    print(form_data)
+    return {"access_token": form_data.username, "token_type": "bearer"}
+
+
+@app.get("/users/profile")
+async def profile(token: str = Depends(oauth_scheme)):
+    print(token)
+    return {
+        "user": "test1",
+        "profile": "myprofile"
+    }
+
+
+@app.get("/report/{id}", response_class=HTMLResponse)
+async def report(request: Request, id: str):
+    return templates.TemplateResponse("index.html", {"request":request, "id": id})
+
+
+
+@app.post("/submitform")
+async def handle_form(request:Request, assignment: str = Form(...), assignment_file: UploadFile = File(...)):
+  print(assignment)
+  print(assignment_file.filename)
+  content_assignment = await assignment_file.read()
+  print(content_assignment)
+  return templates.TemplateResponse("submited.html", {"request": request, "file_name": assignment_file.filename})
+
+
+@app.get("/legacy/")
+def get_legacy_data():
+    data = """<?xml version="1.0"?>
+    <shampoo>
+    <Header>
+        Apply shampoo here.
+    </Header>
+    <Body>
+        You'll have to use soap here.
+    </Body>
+    </shampoo>
+    """
+    return Response(content=data, media_type="application/xml")
+
+
+@app.post("/write/")
+async def writecsv(file: UploadFile = File(...)):
+
+  # file in utf8
+  data = file.file
+  df = pd.read_csv(data, sep=",", skiprows=2, na_values='NULL')
+  db = dataset.connect('mysql://root:pAssw0rd@localhost:3306/keyword?charset=utf8mb4')
+
+  table = db['test3']
+  rows = df.shape[0]
+  for i in range(rows):
+    row = df.iloc[i]
+    table.insert(dict(row))
+
+  db.close()
+
+if __name__ == '__main__':
+  uvicorn.run(app)

+ 20 - 0
archived/test/test3.py

@@ -0,0 +1,20 @@
+from fastapi import APIRouter, Depends, File, UploadFile
+from api.common.logger import logger
+
+router = APIRouter()
+
+# @router.post("/upload/file/", summary="上传图片")
+# async def upload_image( file: UploadFile = File(...) ):
+#     logger.info(f"用户{token_data.sub}->上传文件:{file.filename}")
+#     # 本地存储临时方案,一般生产都是使用第三方云存储OSS(如七牛云, 阿里云)
+#     save_dir = f"{settings.BASE_DIR}/assets"
+#     if not os.path.exists(save_dir):
+#         os.mkdir(save_dir)
+#     try: suffix = Path(file.filename).suffix
+#         with NamedTemporaryFile(delete=False, suffix=suffix, dir=save_dir) as tmp:
+#             shutil.copyfileobj(file.file, tmp)
+#             tmp_file_name = Path(tmp.name).name
+#         finally:
+#             file.file.close()
+#
+#     return response_code.resp_200(data={"image": f"http://127.0.0.1:8010/assets/{tmp_file_name}"})

+ 21 - 0
archived/test/test4.py

@@ -0,0 +1,21 @@
+from fastapi import FastAPI, Request
+from fastapi.responses import HTMLResponse
+from fastapi.staticfiles import StaticFiles
+from fastapi.templating import Jinja2Templates
+
+app = FastAPI()
+
+app.mount("/static", StaticFiles(directory="static"), name="static")
+
+
+templates = Jinja2Templates(directory="templates")
+
+@app.get("/items/{id}", response_class=HTMLResponse)
+async def read_item(request: Request, id: int):
+    x = 0
+    nums = x + 11
+    title = "報表"
+    keyword = "關鍵字1"
+    return templates.TemplateResponse("item.html", {"request": request, "id": id, "num": nums, "titles": title, "keyword":keyword})
+
+

+ 16 - 0
archived/test/treemap1.py

@@ -0,0 +1,16 @@
+# libraries
+import matplotlib.pyplot as plt
+import squarify    # pip install squarify (algorithm for treemap)
+import pandas as pd
+
+# Create a data frame with fake data
+df = pd.DataFrame({'nb_people':[8,3,4,2], 'group':["group A", "group B", "group C", "group D"] })
+
+# plot it
+squarify.plot(sizes=df['nb_people'], label=df['group'], alpha=.8 )
+plt.axis('off')
+# plt.show()
+path = '../img/'
+filename = 'filename.png'
+saved = path + filename
+plt.savefig(saved, dpi = 300)

+ 14 - 0
archived/test/treemap2.py

@@ -0,0 +1,14 @@
+# libraries
+import matplotlib.pyplot as plt
+import squarify    # pip install squarify (algorithm for treemap)
+import pandas as pd
+
+# Create a data frame with fake data
+df=pd.read_csv('../docs/keyword.csv')
+r = df.head()
+
+# # plot it
+# squarify.plot(sizes=df['nb_people'], label=df['group'], alpha=.8 )
+# r = df.head()
+# print(r)
+

+ 17 - 0
archived/test/treemap3.py

@@ -0,0 +1,17 @@
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+import seaborn as sns
+import squarify
+
+data = {'labels': ["影片","剪輯","素材","字幕","錄影","拍攝", "影片 製作","youtuber","影片 剪輯","影片 素材"],
+        'values':[50000,5000,50000,5000,5000,500,5000,50000,50000,5000]}
+df = pd.DataFrame(data)
+colors=['#fae588','#f79d65','#f9dc5c','#e8ac65','#e76f51','#ef233c','#b7094c'] #color palette
+
+sns.set_style(style="whitegrid") # set seaborn plot style
+sizes= df["values"].values# proportions of the categories
+label=df["labels"]
+squarify.plot(sizes=sizes, label=label, alpha=0.6,color=colors).set(title='Treemap with Squarify')
+plt.axis('off')
+plt.savefig("../img/filename.png", dpi = 300)

+ 17 - 0
archived/test/treemap4.py

@@ -0,0 +1,17 @@
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+import seaborn as sns
+import squarify
+
+data = {'labels': ["video","editing","resource","Subtitle","record","film", "video produce","youtuber","video editing","video resource"],
+        'values':[50000,5000,50000,5000,5000,500,5000,50000,50000,5000]}
+df = pd.DataFrame(data)
+colors=['#fae588','#f79d65','#f9dc5c','#e8ac65','#e76f51','#ef233c','#b7094c'] #color palette
+
+sns.set_style(style="whitegrid") # set seaborn plot style
+sizes= df["values"].values# proportions of the categories
+label=df["labels"]
+squarify.plot(sizes=sizes, label=label, alpha=0.6,color=colors).set(title='Treemap with Squarify')
+plt.axis('off')
+plt.savefig("../img/filename.png", dpi = 300)

+ 24 - 0
archived/test/treemap5.py

@@ -0,0 +1,24 @@
+# import matplotlib.pyplot as plt
+# import squarify
+# sizes = [40, 50, 30, 2]
+# label = ["a", "b", "c", "d"]
+# color = ["red", "blue", "green", "grey"]
+# squarify.plot(sizes=sizes, label=label, color=color, alpha=0.6)
+# plt.axis('off')
+# plt.show()
+import matplotlib.pyplot as plt
+import seaborn as sns
+import squarify
+
+rawdata = sns.load_dataset('titanic')
+# print(rawdata.head())
+n = rawdata.groupby('class')[['survived']].sum()
+# print(n)
+a = rawdata.groupby('class')[['survived']].sum().index.get_level_values(0).tolist()#取得index裡的[0]再轉為list
+# print(a)
+d = rawdata.groupby('class')[['survived']].sum().reset_index().survived.values.tolist()#This gives us the labels in the form of a list. To get the values corresponding to these labels, use :
+# print(d)
+
+squarify.plot(sizes=d, label=a, alpha=.8)
+plt.axis('off')
+plt.show()

+ 21 - 0
archived/test/treemap6.py

@@ -0,0 +1,21 @@
+import matplotlib.pyplot as plt
+import seaborn as sns
+import squarify
+import pandas as pd
+
+rawdata = pd.read_csv('../docs/keyword.csv')
+
+
+# rawdata = sns.load_dataset(df)
+# print(rawdata.head())
+# n = rawdata.groupby('Competition')[['Avg. monthly searches']].sum()
+# print(n)
+
+a = rawdata.groupby('Keyword')[['Avg_monthly_searches']].sum().index.get_level_values(0).tolist()#取得index裡的[0]再轉為list
+print(a)
+d = rawdata.groupby('Keyword')[['Avg_monthly_searches']].sum().reset_index().Avg_monthly_searches.values.tolist()#This gives us the labels in the form of a list. To get the values corresponding to these labels, use :
+print(d)
+plt.rcParams['font.sans-serif'] = ['Taipei Sans TC Beta']
+squarify.plot(sizes=d, label=a, alpha=.8)
+plt.axis('off')
+plt.show()

+ 75 - 0
archived/test/treemap7.py

@@ -0,0 +1,75 @@
+# #import some lib
+# import numpy as np # linear algebra
+# import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
+# import matplotlib.pyplot as plt
+# import seaborn as sns
+#
+# color = sns.color_palette()
+# # %matplotlib inline
+# pd.options.mode.chained_assignment = None# default='warn'
+# order_products_prior_df = pd.read_csv("../docs/keyword.csv")
+# # aisles_df = pd.read_csv("../input/aisles.csv")
+# # departments_df = pd.read_csv("../input/departments.csv")
+# # order_products_prior_df = pd.merge(products_df, aisles_df, on='aisle_id', how='left')
+# # order_products_prior_df = pd.merge(order_products_prior_df, departments_df, on='department_id', how='left')
+# order_products_prior_df.head()
+#
+# import matplotlib
+# import squarify
+#
+# temp = order_products_prior_df[['keyword','Avg_monthly_searches']]
+# temp = pd.concat([
+# order_products_prior_df.groupby('keyword')['Avg_monthly_searches'].nunique().rename('Avg_monthly_searches')
+# # order_products_prior_df.groupby('department')['aisle'].nunique().rename('aisle_department')
+# ], axis=1).reset_index()
+# temp = temp.set_index('keyword')
+# temp2 = temp.sort_values(by="Avg_monthly_searches", ascending=False)
+#
+# # TreeMap parameters
+# x = 0.
+# y = 0.
+# width = 100.
+# height = 100.
+# cmap = matplotlib.cm.viridis
+#
+# # color scale on the population
+# # min and max values without Pau
+# mini, maxi = temp2.products_department.min(), temp2.products_department.max()
+# norm = matplotlib.colors.Normalize(vmin=mini, vmax=maxi)
+# colors = [cmap(norm(value)) for value in temp2.products_department]
+# colors[1] = "#FBFCFE"
+#
+# # labels for squares
+# labels = ["%s/n%d search num keyword num" % (label)
+#           for label in zip(temp2.index, temp2.Avg_monthly_searches)]
+#
+# # make plot
+# fig = plt.figure(figsize=(12, 10))
+# fig.suptitle("search keyword", fontsize=20)
+# ax = fig.add_subplot(111, aspect="equal")
+# ax = squarify.plot(temp2.Avg_monthly_searches, color=colors, label=labels, ax=ax, alpha=.7)
+# ax.set_xticks([])
+# ax.set_yticks([])
+# # color bar
+# # create dummy invisible image with a color map
+# img = plt.imshow([temp2.Avg_monthly_searches], cmap=cmap)
+# img.set_visible(False)
+# fig.colorbar(img, orientation="vertical", shrink=.96)
+# fig.text(.76, .9, "numbers of products", fontsize=14)
+# fig.text(.5, 0.1,
+# "powered by CJ /n keyword totale %d" % (temp2.Avg_monthly_searches.sum()), fontsize=14, ha="center")
+# fig.text(.5, 0.07,
+# "Source : http://netfly",
+# fontsize=14,
+# ha="center")
+# plt.show()
+
+import matplotlib.pyplot as plt
+
+plt.rcParams['font.sans-serif'] = ['Taipei Sans TC Beta']
+
+sales = [100, 80, 50]
+x_labels = ['A品牌', 'B品牌', 'C品牌']
+
+plt.bar(x_labels, sales)
+plt.show()

+ 12 - 0
api/heatmap.py → archived/test/treemap8.py

@@ -13,6 +13,18 @@ margin = df['Top of page bid (low range)']
 remark = df['Keyword']
 
 
+# 預處理刪掉不要的data
+# # Create chart and store as figure [fig]
+# fig = px.sunburst(df,
+#                  path=[keyword, bid],
+#                  values=search,
+#                  color=margin,
+#                  color_continuous_scale=['green', 'yellow', 'red'],
+#                  title='Keyword Overview',
+#                  hover_name=remark
+#                  )
+
+
 # Create chart and store as figure [fig]
 fig = px.treemap(df,
                  path=[keyword, bid],

+ 12 - 0
archived/test/treemap9.py

@@ -0,0 +1,12 @@
+import plotly.express as px
+import numpy as np
+df = px.data.gapminder().query("year == 2007")
+fig = px.treemap(df,
+                 path=[px.Constant("world"), 'continent', 'country'],
+                 values='pop',
+                 color='lifeExp',
+                 hover_data=['iso_alpha'],
+                 color_continuous_scale='RdBu',
+                 color_continuous_midpoint=np.average(df['lifeExp'],weights=df['pop']))
+fig.update_layout(margin = dict(t=50, l=25, r=25, b=25))
+fig.show()

+ 261 - 0
archived/test/wordcloud1.py

@@ -0,0 +1,261 @@
+# coding: utf-8
+"""
+Rewritten from Github
+"""
+import jieba
+import matplotlib.pyplot as plt
+import numpy as np
+import random
+from PIL import Image
+from wordcloud import WordCloud
+from scipy.ndimage import gaussian_gradient_magnitude
+
+
+# Load
+text = """
+在我的筆電鍵盤上,F11 和 F12 一直都是調整螢幕亮度的快捷鍵,就像下面這張圖片一樣:
+不過這個圖示好看歸好看,但是在我的筆電上從來都沒辦法用他們來調整螢幕亮度 (正常的 F11、F12 功能還是可以用)。為了保險起見,我還使用 xev 測試看看有沒有抓到 Keycode,不過自然是抓得到的。
+今天想要紀錄的就是,我如何將這兩個按鍵設置為調整螢幕亮度的快捷鍵,搞不好會有一樣問題的人可以參考看看。
+在我的系統上,我的亮度設定是位於 “/sys/class/backlight/intel_backlight/” 這個路徑底下。你的路徑可能與我不同,不過大致上都會在 “/sys/class/backlight/” 底下。
+其中,max_brightness 是我系統上可以設定的亮度最大值,為 120000;brightness 則是我系統當前設定的值,只要更動這個檔案內的數值,我電腦螢幕的亮度也會隨之改變。
+所以要做的第一件事情,就是將 brightness 這份檔案設定權限,讓我可以在一般模式時就能寫入它。
+若是我要減少亮度,我可以使用以下指令:
+若是我要提昇亮度,則就將 “-” 換成 “+” 即可。
+確認這兩個指令沒有問題,就可以將其設定為快捷鍵了。
+其實設定快捷鍵也是相當簡單,在此我簡單做個示範、不過大部份桌面環境設定快捷鍵的方式都大同小異。
+基本上,搜尋 “Shortcut”,應該就能直接找到設定快捷鍵的地方。
+設定快捷鍵有三個參數要填入: Name、Command、Shortcut。
+Name: 無所謂,填入喜歡的名稱即可
+Command: 填入上方調整螢幕亮度的指令
+Shortcut: 按下你想要的快捷鍵,以我這裡為例便是 F11、F12
+完成設置後,我就能成功假裝我的按鍵是正常可以用的了 XDD
+在 Python 中,我們若是想要將一段文本依照『特定字元』來切割,讓文本變成一段段的 List 資料型態儲存著,我們可以簡單地使用 split() 這個函式來完成。
+而 splitlines() 這個函式與 split() 非常相像,不過 splitlines() 是專門處理換行符號的,並且在處理時還能選擇是否保留著換行符號,非常好用。
+假設我們有著以下這樣的文本:
+假設我們想要以空格符號 ” ” 為切割點,我們得到的結果應如下:
+for word in text.split():
+    print(word)
+Output:
+除了預設的以『空格符號』切割外,我們也可以自己選擇換行符號 “\n” 來進行切割。
+Today is a nice day.
+This is a good day.
+Hello! How are you?
+不過在以換行符號 “\n” 切割的時候,split() 是沒有比 splitlines() 方便的,以下我們就來看看 splitlines() 的範例。
+splitlines() 比 split() 優秀的地方在於,我們的文本中很有可能並不僅僅只存在著 “\n” 這樣單純的換行, “\r”、”\r\n”、”\n” 等等也都會被視作換行。
+根據我的經驗,同時考慮 “\r”、”\r\n”、”\n” 三種情況的切割點效果比較好,畢竟不會出現應該換行卻沒有被切割的句子。
+同時,splitlines() 還可以透過 keepends 參數決定是否在輸出結果中保留『換行符號』,在某些情況是非常有用的。
+'\n'
+'Today is a nice day.\n'
+'This is a good day.\n'
+'Hello! How are you?\n'
+這裡我使用了 pprint 來顯示換行符號。值得一提的是 keepends 若為 True 表示保留換行符號;反之,則不保留。
+使用 FastText 訓練詞向量
+FastText 是由 Facebook AI Research Lab (FAIR) 所開發的『詞嵌入』以及『文本分類』,支援 294 種語言,並且使用類神經網路訓練詞嵌入模型。
+基本上 FastText 的演算法是基於以下這兩篇論文:
+Enriching Word Vectors with Subword Information
+Bag of Tricks for Efficient Text Classification
+不過介紹了這麼多,今天我主要的目的是要介紹如何在 Python 中透過 Gensim 套件快速地調用 FastText 訓練一個 Word Embedding 的模型。基本上流程都與 Gensim 中本來訓練 Word2Vec 極度相像。
+以下就直接來看程式碼。值得一提的是,由於我之前寫過使用 Gensim 訓練 Word2Vec 模型,所以有部份相同的流程我是直接從那邊抄來的 XDD
+安裝 Gensim
+首先,如果你的環境裡沒有 Gensim,使用以下指令安裝:
+pip3 install gensim
+Python is the most popular programming language!
+前言
+FastText 是由 Facebook AI Research Lab (FAIR) 所開發的『詞嵌入』以及『文本分類』,支援 294 種語言,並且使用類神經網路訓練詞嵌入模型。
+基本上 FastText 的演算法是基於以下這兩篇論文:
+Enriching Word Vectors with Subword Information
+Bag of Tricks for Efficient Text Classification
+不過介紹了這麼多,今天我主要的目的是要介紹如何在 Python 中透過 Gensim 套件快速地調用 FastText 訓練一個 Word Embedding 的模型。基本上流程都與 Gensim 中本來訓練 Word2Vec 極度相像。
+以下就直接來看程式碼。值得一提的是,由於我之前寫過使用 Gensim 訓練 Word2Vec 模型,所以有部份相同的流程我是直接從那邊抄來的 XDD
+安裝 Gensim
+首先,如果你的環境裡沒有 Gensim,使用以下指令安裝:
+pip3 install gensim
+下載 WIKI 語料
+這裡以 Wiki 上的中文資料為訓練語料,Wiki 上的資料可是相當優秀的。不僅量多、而且詞彙涵蓋範圍廣,可以應用在許多不同的任務上。
+可以從這個網址找到下載處:https://zh.wikipedia.org/wiki/Wikipedia:%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8B%E8%BD%BD
+進入之後可以直接選擇一個日期,那是不同時間點的資料備份。
+比如說我選擇了 20200101 這個時間點的資料,那麼,我要下載的資料則為:zhwiki-20200101-pages-articles-multistream.xml.bz2
+要注意的是,你的日期可能與我不同,不過同樣都是這份檔案。
+下載之後不用解壓縮,可以使用 Gensim 裡的工具直接提取文章。
+WikiCorpus
+WikiCorpus 是 Gensim 裡面的一個模組,專門用於清理 Wiki 資料庫中語料不必要的標籤,使其恢復成乾淨的文本。
+# coding: utf-8
+Extracted the content in the wiki_database
+from gensim.corpora import WikiCorpus
+# Load data
+wiki_corpus = WikiCorpus('../data/zhwiki-latest-pages-articles-multistream.xml.bz2', dictionary={})
+# Save data
+with open('wiki_text.txt', 'w', encoding='utf-8') as f:
+    print('Start to preprocess.')
+    for times, text in enumerate(wiki_corpus.get_texts()):
+        f.write(' '.join(text)+'\n')
+        if (times+1) % 10000 == 0:
+            print(times+1)
+順帶一提,WikiCorpus() 函式當中的路徑為我下載的語料資料,你的名稱可能與我不同、也需要對應到你下載的路徑。
+儲存之後的效果應如下:
+斷詞
+『斷詞』這項工作指的是文本分成以『詞』為單位的句子。斷詞的工具有很多種,基本上可以參考我之前寫過的:
+NLP 繁體中文斷詞的霸主 —— CKIP
+NLP 中文斷詞最方便的開源工具之一 —— Jieba
+中文自然語言分析的工具包 —— THULAC
+多功能的自然語言處理工具 —— HanLP
+如果想要對繁體中文斷詞效果最好,首推 CKIP;如果是要斷詞速度的話,那非 Jieba 莫屬。在這裡以 Jieba 示範。
+(註:Wiki 的資料當中許多地方是簡繁混雜的,可以考慮使用 OpenCC 這項工具來轉換。詳細的作法可以參閱我之前撰寫過的《中文繁簡轉換的便利工具 —— OpenCC》)
+# coding: utf-8
+Tokenize
+import jieba
+from opencc import OpenCC
+# Initial
+cc = OpenCC('s2t')
+# Tokenize
+with open('wiki_text_seg.txt', 'w', encoding='utf-8') as new_f:
+    with open('wiki_text.txt', 'r', encoding='utf-8') as f:
+        for data in f:
+            data = cc.convert(data)
+            data = jieba.cut(data)
+            data = [word for word in data if word != ' ']
+            data = ' '.join(data)
+
+            new_f.write(data)
+斷詞結果展示如下:
+歐幾
+裏
+得
+西元前
+三世
+紀的
+古希臘
+數學家
+現在
+被
+認為
+是
+幾何
+之父
+此畫
+為拉斐爾
+的
+作品
+雅典
+學院
+數學
+是
+利用
+…
+最後,終於來到呼叫 FastText 來訓練模型了。
+使用 FastText 訓練模型
+# coding: utf-8
+from gensim.models import word2vec, fasttext
+# Settings
+seed = 666
+sg = 0
+window_size = 10
+vector_size = 100
+min_count = 1
+workers = 8
+epochs = 5
+batch_words = 10000
+# Train
+train_data = word2vec.LineSentence('wiki_text_seg.txt')
+model = fasttext.FastText(
+    train_data,
+    min_count=min_count,
+    size=vector_size,
+    workers=workers,
+    iter=epochs,
+    window=window_size,
+    sg=sg,
+    seed=seed,
+    batch_words=batch_words,
+)
+model.save('fasttext.model')
+這裡也解釋一下模型中各個參數的意義:
+seed: 亂數種子
+sg: Word2Vec 有兩種算法,CBOW 以及 Skip-gram,這裡選擇了訓練比較快的 CBOW
+window_size: 周圍詞彙要看多少範圍
+size: 轉成向量的維度
+min_count: 詞頻少於 min_count 之詞彙不會參與訓練
+workers: 訓練的並行數量
+iter: 訓練的迭代次數
+batch_words:每次給予多少詞彙量訓練
+訓練結束以後,我將模型儲存為 “fasttext.model”。
+測試模型效果
+# coding: utf-8
+Test the w2v model
+from gensim.models import word2vec
+# Load the model
+model = word2vec.Word2Vec.load('models/fasttext.model')
+# Test
+print(model['生物'].shape)
+for item in model.most_similar('生物'):
+print(item)
+model.save('fasttext.model')
+Output:
+(100,)
+('若好', 0.9359757900238037)
+('身半', 0.9298930764198303)
+('過金', 0.9281899929046631)
+('低等生物', 0.9252755641937256)
+('腐生物', 0.9232699275016785)
+('過金魅', 0.9228056073188782)
+('生物能', 0.9225305914878845)
+('捉酸蟲', 0.9221773743629456)
+('非生物', 0.9185526371002197)
+('過金貝', 0.9147799015045166)
+不知道是不是我的錯覺,我覺得 Gensim 訓練 Word2Vec 模型感覺效果比較好。
+"""
+
+
+# Tokenize
+text = ' '.join(jieba.cut(text))
+
+
+# Mask image
+mask_color = np.array(Image.open('./parrot-by-jose-mari-gimenez2.jpg'))
+mask_color = mask_color[::3, ::3]
+mask_image = mask_color.copy()
+mask_image[mask_image.sum(axis=2) == 0] = 255
+
+
+# Edge detection
+edges = np.mean([gaussian_gradient_magnitude(mask_color[:, :, i]/255., 2) for i in range(3)], axis=0)
+mask_image[edges > .08] = 255
+
+
+# WordCloud
+wc = WordCloud(max_words=2000,
+               mask=mask_image,
+               # font_path='fonts/DFXingKaiStd-W5.otf',
+               max_font_size=40,
+               random_state=42,
+               relative_scaling=0)
+
+wc.generate(text)
+
+
+# Create coloring from image
+def color_func(word, font_size, position, orientation, random_state=None, **kwargs):
+    return 'hsl(51, 100%%, %d%%)' % random.randint(40, 60)
+
+
+wc.recolor(color_func=color_func)
+
+
+# Plot
+plt.figure()
+plt.axis('off')
+plt.imshow(wc)
+plt.show()
+
+
+# Save
+plt.figure()
+plt.axis('off')
+fig = plt.imshow(wc, interpolation='nearest')
+fig.axes.get_xaxis().set_visible(False)
+fig.axes.get_yaxis().set_visible(False)
+plt.savefig('test.png',
+            bbox_inches='tight',
+            pad_inches=0,
+            format='png',
+            dpi=300)

+ 7 - 0
archived/test/wordcloud2.py

@@ -0,0 +1,7 @@
+import nltk
+from wordcloud import WordCloud
+
+text = open('data.txt', 'r', encoding='utf-8').read()
+text = ' '.join(nltk.word_tokenize(text))
+cloud = WordCloud().generate(text)
+cloud.to_file('output.png')

+ 32 - 0
archived/test/wordcloud3.py

@@ -0,0 +1,32 @@
+import csv
+from wordcloud import WordCloud
+
+
+#read first column of csv file to string of words seperated
+#by tab
+
+your_list = []
+with open('keyword2.csv', 'r') as f:
+    reader = csv.reader(f)
+    your_list = '\t'.join([i[1] for i in reader])
+
+
+# Generate a word cloud image
+wordcloud = WordCloud().generate(your_list)
+
+# Display the generated image:
+# the matplotlib way:
+import matplotlib.pyplot as plt
+plt.imshow(wordcloud, interpolation='bilinear')
+plt.axis("off")
+
+# lower max_font_size
+wordcloud = WordCloud(max_font_size=40).generate(your_list)
+plt.figure()
+plt.imshow(wordcloud, interpolation="bilinear")
+plt.axis("off")
+plt.show()
+
+# The pil way (if you don't have matplotlib)
+# image = wordcloud.to_image()
+# image.show()

+ 20 - 0
core/config.py

@@ -0,0 +1,20 @@
+import os
+from dotenv import load_dotenv
+
+from pathlib import Path
+env_path = Path('.') / '.env'
+load_dotenv(dotenv_path=env_path)
+
+
+class Settings:
+    PROJECT_NAME:str = "Dash Board"
+    PROJECT_VERSION: str = "1.0.0"
+
+    POSTGRES_USER: str = os.getenv("POSTGRES_USER")
+    POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD")
+    POSTGRES_SERVER: str = os.getenv("POSTGRES_SERVER", "localhost")
+    POSTGRES_PORT: str = os.getenv("POSTGRES_PORT", 5432)  # default postgres port is 5432
+    POSTGRES_DB: str = os.getenv("POSTGRES_DB", "tdd")
+    DATABASE_URL = f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_SERVER}:{POSTGRES_PORT}/{POSTGRES_DB}"
+
+settings = Settings()

+ 18 - 0
db/session.py

@@ -0,0 +1,18 @@
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+
+from core.config import settings
+
+
+# SQLALCHEMY_DATABASE_URL = settings.DATABASE_URL
+# engine = create_engine(SQLALCHEMY_DATABASE_URL)
+
+#if you don't want to install postgres or any database, use sqlite, a file system based database,
+# uncomment below lines if you would like to use sqlite and comment above 2 lines of SQLALCHEMY_DATABASE_URL AND engine
+
+SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
+engine = create_engine(
+    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
+)
+
+SessionLocal = sessionmaker(autocommit=False,autoflush=False,bind=engine)

+ 124 - 0
main.py

@@ -0,0 +1,124 @@
+from fastapi import FastAPI
+from fastapi.staticfiles import StaticFiles
+from apis.general_pages.route_homepage import general_pages_router
+from core.config import settings
+
+
+# import pandas as pd
+# from fastapi import FastAPI, File, UploadFile, Request
+# from fastapi.middleware.cors import CORSMiddleware
+# import dataset
+# from functools import reduce
+# from fastapi.staticfiles import StaticFiles
+# from fastapi.templating import Jinja2Templates
+# from fastapi.responses import HTMLResponse
+
+
+
+# app = FastAPI()
+# app.add_middleware(
+#     CORSMiddleware,
+#     allow_origins=['*'],
+#     allow_credentials=True,
+#     allow_methods=["*"],
+#     allow_headers=["*"],
+# )
+
+# templates = Jinja2Templates(directory="templates")
+#
+# app.mount("/static", StaticFiles(directory="static"), name="static")
+
+# @app.get("/")
+# def hello_api():
+#     return {"msg":"Hello API"}
+
+def include_router(app):
+    app.include_router(general_pages_router)
+
+def configure_static(app):
+    app.mount("/static", StaticFiles(directory="static"), name="static")
+
+def start_application():
+    app = FastAPI(title=settings.PROJECT_NAME,version=settings.PROJECT_VERSION)
+    include_router(app)
+    return app
+
+
+app = start_application()
+
+
+# @app.post("/write/")
+# async def writecsv(file: UploadFile = File(...)):
+#
+#     # read csv
+#     repls = (' Stats ', '_'), (' at ', '_'), ('-', '_'), \
+#             (' ', ''), ('.csv', '')
+#     filename = file.filename
+#     filename = reduce(lambda a, kv: a.replace(*kv), repls, filename)
+#
+#     data = file.file
+#     df = pd.read_csv(data, sep=",",
+#                      skiprows=0, na_values='NULL')
+#
+#     # db connect
+#     # db = dataset.connect(
+#     #     'mysql://choozmo:pAssw0rd@db.ptt.cx:3306/keywordweb?charset=utf8mb4'
+#     # )
+#     db = dataset.connect(
+#         'mysql://root:pAssw0rd@localhost:3306/keywordweb?charset=utf8mb4'
+#     )
+#     sql = "CREATE TABLE IF NOT EXISTS "\
+#           + filename +\
+#           "(ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, " \
+#           "keyword VARCHAR(100), " \
+#           "currency VARCHAR(100), avg_monthly_searches VARCHAR(100), " \
+#           "three_month_change VARCHAR(100), " \
+#           "yearly_change VARCHAR(100), competition VARCHAR(100), " \
+#           "competition_indexed VARCHAR(100), " \
+#           "top_page_bid_low_range VARCHAR(100), " \
+#           "top_page_bid_hi_range VARCHAR(100)" \
+#           ");"
+#
+#     db.query(sql)
+#
+#     # write to db
+#     table = db[filename]
+#     lines = df.shape
+#     i = 0
+#
+#     rows = lines[0]
+#
+#     for i in range(rows):
+#         row1 = df.iloc[i]
+#         k = row1[0]
+#         c = row1[1]
+#         a = row1[2]
+#         t = row1[3]
+#         y = row1[4]
+#         c1 = row1[5]
+#         c2 = row1[6]
+#         t1 = row1[7]
+#         t2 = row1[8]
+#
+#         dbdata = dict(keyword=k, currency=c, avg_monthly_searches=a,
+#                       three_month_change=t, yearly_change=y, competition=c1,
+#                       competition_indexed=c2, top_page_bid_low_range=t1,
+#                       top_page_bid_hi_range=t2)
+#         table.insert(dbdata)
+#
+#     db.close()
+#
+#
+#
+# @app.get("/items/{id}", response_class=HTMLResponse)
+# async def read_item(request: Request, id: int):
+#     x = 0
+#     nums = x + 11
+#     title = "報表"
+#     keyword = "關鍵字1"
+#     return templates.TemplateResponse(
+#         "item.html",
+#         {"request": request, "id": id,
+#          "num": nums, "titles": title, "keyword":keyword
+#          })
+#

+ 15 - 0
requirements.txt

@@ -0,0 +1,15 @@
+fastapi
+uvicorn
+
+#for template  #new
+jinja2
+
+#for static files
+aiofiles
+
+#for database   #new
+sqlalchemy         
+psycopg2
+
+#for loading environment variables  #new
+python-dotenv

BIN
result/img.jpg


BIN
static/images/fastapi.png


BIN
static/images/logo.png


+ 15 - 0
static/styles.css

@@ -0,0 +1,15 @@
+.box {
+  margin: 0 auto;
+}
+
+.box h1 {
+  color: aqua;
+}
+
+img {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+  width: 50%;
+}
+/*# sourceMappingURL=styles.css.map */

+ 9 - 0
static/styles.css.map

@@ -0,0 +1,9 @@
+{
+    "version": 3,
+    "mappings": "AAAA,AAAA,IAAI,CAAC;EACD,MAAM,EAAE,MAAM;CAEjB;;AAHD,AAEI,IAFA,CAEA,EAAE,CAAC;EAAE,KAAK,EAAE,IAAI;CAAI;;AAGxB,AAAA,GAAG,CAAC;EACA,OAAO,EAAE,KAAK;EACd,WAAW,EAAE,IAAI;EACjB,YAAY,EAAE,IAAI;EAClB,KAAK,EAAE,GAAG;CACb",
+    "sources": [
+        "styles.scss"
+    ],
+    "names": [],
+    "file": "styles.css"
+}

+ 12 - 0
static/styles.scss

@@ -0,0 +1,12 @@
+.box {
+    margin: 0 auto;
+    h1 { color: aqua; }
+}
+
+img {
+    display: block;
+    margin-left: auto;
+    margin-right: auto;
+    width: 50%;
+}
+

+ 36 - 0
templates/components/navbar.html

@@ -0,0 +1,36 @@
+<nav class="navbar navbar-expand-lg navbar-light bg-light">
+  <div class="container-fluid">
+    <a class="navbar-brand" href="#"></a>
+    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+      <span class="navbar-toggler-icon"></span>
+    </button>
+    <div class="collapse navbar-collapse" id="navbarSupportedContent">
+      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
+        <li class="nav-item">
+          <a class="nav-link active" aria-current="page" href="#">Home</a>
+        </li>
+        <li class="nav-item">
+          <a class="nav-link" href="#">Link</a>
+        </li>
+        <li class="nav-item dropdown">
+          <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
+            Dropdown
+          </a>
+          <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
+            <li><a class="dropdown-item" href="#">Action</a></li>
+            <li><a class="dropdown-item" href="#">Another action</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" href="#">Something else here</a></li>
+          </ul>
+        </li>
+        <li class="nav-item">
+          <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
+        </li>
+      </ul>
+      <form class="d-flex">
+        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
+        <button class="btn btn-outline-success" type="submit">Search</button>
+      </form>
+    </div>
+  </div>
+</nav>

+ 93 - 0
templates/general_pages/homepage.html

@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta name="fastapitutorial.com" content="Nofoobar">
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet"
+    integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
+</head>
+<body>
+    <h1 class="display-4">The Dash Board</h1>
+    <canvas id="bar-yt" width="400" height="200"></canvas>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.2/chart.min.js"
+      integrity="sha512-tMabqarPtykgDtdtSqCL3uLVM0gS1ZkUAVhRFu1vSEFgvB73niFQWJuvviDyBGBH22Lcau4rHB5p2K2T0Xvr6Q=="
+      crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
+    <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js'></script>
+    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"
+      integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p"
+      crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.min.js"
+      integrity="sha384-Atwg2Pkwv9vp0ygtn1JAojH0nYbwNJLPhwyoVbhoPwBhjQPR5VtM2+xf0Uwh9KtT"
+      crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.18/dist/sweetalert2.all.min.js"></script>
+    <script src="https://kit.fontawesome.com/0b8ff4e055.js" crossorigin="anonymous"></script>
+    <script>
+      var ctx10 = document.getElementById('bar-yt');
+      var myChart10 = new Chart(ctx10, {
+        type: 'bar', //圖表類型
+        data: {
+          //標題
+          labels: [ "{{ id }}", '那些足球教我的事'],
+          datasets: [
+            {
+              label: '月搜量',
+              data: [50, 11],
+              borderColor: 'rgba(255, 206, 86, 1)',
+              backgroundColor: 'rgba(255, 206, 86, 1)',
+            },
+            {
+              label: '金額',
+              data: [40.57, 91.72],
+              borderColor: 'rgba(255, 99, 132, 1)',
+              backgroundColor: 'rgba(255, 99, 132, 1)',
+            },
+          ],
+        },
+        options: {
+          // indexAxis: 'y',
+          plugins: {
+            legend: {
+              // display: false,
+              labels: {
+                padding: 5,
+                font: {
+                  display: false,
+                  size: 16,
+                },
+              },
+            },
+          },
+          scales: {
+            x: {
+              ticks: {
+                font: {
+                  size: 16,
+                }
+              },
+              title: {
+                display: false,
+                font: {
+                  family: 'Times',
+                  size: 48,
+                },
+              },
+            },
+            y: {
+              title: {
+                display: true,
+              },
+              ticks: {
+                font: {
+                  size: 16,
+                }
+              },
+              beginAtZero: true,
+            }
+          }
+        }
+      });
+    </script>
+</body>
+</html>

BIN
templates/general_pages/logo.png


+ 28 - 0
templates/shared/base.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta name="fastapitutorial.com" content="Nofoobar">
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
+
+    {% block title %}
+    {% endblock %}
+</head>
+
+<body>
+    {% include "components/navbar.html" %}
+    {% block content %}
+    {% endblock %}
+
+    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
+    
+    
+    
+    
+    {% block scripts %}
+    {% endblock %}
+
+
+</body>
+</html>

Vissa filer visades inte eftersom för många filer har ändrats