File size: 8,716 Bytes
83e7365
8309961
83e7365
 
d79f5f2
83e7365
d79f5f2
 
83e7365
 
 
09ec489
d79f5f2
9a62435
 
d79f5f2
 
 
83e7365
 
 
 
eca6f3a
 
 
 
83e7365
d79f5f2
de7f21d
 
 
39977eb
d79f5f2
 
 
 
 
 
 
00cd8e1
d79f5f2
 
5784cf3
7b96f10
97cd51a
 
 
5784cf3
77f112d
 
5784cf3
 
77f112d
5784cf3
 
 
77f112d
 
 
 
82eb64f
00cd8e1
82eb64f
 
 
 
 
 
 
 
0bad7a3
 
 
82eb64f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471d917
82eb64f
4e6be8d
 
 
 
38482e4
 
82eb64f
 
 
 
 
 
8309961
 
00cd8e1
8309961
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
00cd8e1
8309961
 
 
bd68530
00cd8e1
 
 
 
 
8309961
bd68530
00cd8e1
 
 
 
 
83e7365
 
 
 
 
 
 
 
 
 
 
eca6f3a
cabe12b
 
83e7365
 
 
 
 
 
eca6f3a
83e7365
cabe12b
eca6f3a
 
 
83e7365
 
 
 
 
eca6f3a
 
83e7365
eca6f3a
e4aa4a9
bd68530
7b96f10
bd68530
 
 
 
 
 
 
 
 
 
 
 
 
 
7b96f10
 
62a652e
115ff47
647ff2a
 
 
 
 
 
 
 
 
 
29a572c
647ff2a
 
 
29a572c
62a652e
115ff47
647ff2a
 
 
115ff47
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import os
import json
import logging
from datetime import datetime, timedelta, date
from typing import List
from dataclasses import asdict

import gradio as gr
from google.oauth2.service_account import Credentials
from google.cloud import bigquery

from utils.mes_player_model import Player

AVATAR_PATH = "avatar/"
AVATAR_FILE_TYPE = ".png"
MEDIA_PATH = "medias/"
MEDIA_FILE_TYPE = ".png"

SCOPES = ["https://www.googleapis.com/auth/bigquery"]
SERVICE_ACCOUNT_INFO = os.getenv("GBQ_TOKEN")
service_account_info_dict = json.loads(SERVICE_ACCOUNT_INFO)

creds = Credentials.from_service_account_info(service_account_info_dict, scopes=SCOPES)
client = bigquery.Client(
    credentials=creds, project=service_account_info_dict["project_id"]
)


def get_content(file_name: str) -> str:
    with open(file_name, "r", encoding="utf-8") as file:
        content = file.read()
    return content


def get_player_partners(player_info: gr.State) -> List[str]:
    return [
        f"{MEDIA_PATH}{partner}{MEDIA_FILE_TYPE}" for partner in player_info["partners"]
    ]


def get_player_badges(player_info: gr.State) -> List[str]:
    return [f"{MEDIA_PATH}{badge}{MEDIA_FILE_TYPE}" for badge in player_info["badges"]]


def get_player_avatar(player_info: gr.State) -> str:
    return f"{AVATAR_PATH}avatar_{player_info['player_group'] + 1}{AVATAR_FILE_TYPE}"


def get_player_adventure_logs(player_info: gr.State) -> List[str]:
    log_template = """<div class="adventure"><p>{player_log}</p></div>"""
    return [
        log_template.format(player_log=player_log)
        for player_log in player_info["adventure_logs"]
    ]


def get_player_adventure_logs_html(player_info: gr.State) -> str:
    adventure_logs = "".join(get_player_adventure_logs(player_info))
    template_content = get_content("htmls/adventure_template.html")
    return template_content.replace("{logs}", adventure_logs)


def get_player_achievements(player_info: gr.State) -> List[str]:
    achivement_name_map = {
        "participation_star": "參賽之星",
        "star_score_settler": "星際積分領航者",
        "interstellar_traveler_I": "星際旅行者 I",
        "interstellar_traveler_II": "星際旅行者 II",
        "interstellar_traveler_III": "星際旅行者 III",
        "interstellar_traveler_IV": "星際旅行者 IV",
        "climbers_club_I": "爬升俱樂部 I",
        "climbers_club_II": "爬升俱樂部 II",
        "climbers_club_III": "爬升俱樂部 III",
        "star_cluster_detector": "星團探測官",
        "starry_vigilante": "群星瞭望者",
        "planetary_decoder": "行星解碼",
        "galactic_librarian": "星系圖書館員",
        "energy_enthusiast_I": "能量狂熱者 I",
        "energy_enthusiast_II": "能量狂熱者 II",
        "energy_enthusiast_III": "能量狂熱者 III",
        "energy_enthusiast_IV": "能量狂熱者 IV",
        "knowledge_planet_explorer_I": "知識星球探險家 I",
        "knowledge_planet_explorer_II": "知識星球探險家 II",
        "scientific_expedition_explorer_I": "科學探險探險家 I",
        "scientific_expedition_explorer_II": "科學探險探險家 II",
        "cultural_celebration_explorer_I": "文化慶典探險家 I",
        "cultural_celebration_explorer_II": "文化慶典探險家 II",
        "youth_literature_explorer_I": "青春文學探險家 I",
        "youth_literature_explorer_II": "青春文學探險家 II",
        "path_to_wealth_explorer_I": "財富之路探險家 I",
        "path_to_wealth_explorer_II": "財富之路探險家 II",
        "cultivation_universe_explorer_I": "素養宇宙探險家 I",
        "cultivation_universe_explorer_II": "素養宇宙探險家 II",
        "electronic_and_information_college_explorer_I": "電資學院探險家 I",
        "electronic_and_information_college_explorer_II": "電資學院探險家 II",
        "star_warrior": "星空艦長",
    }
    if not isinstance(player_info["rewards_status"], dict):
        rewards_status = json.loads(player_info["rewards_status"])
    else:
        rewards_status = player_info["rewards_status"]
    if "routine_checker" in rewards_status:
        del rewards_status["routine_checker"]
    return [
        (
            achivement_name_map[achievement_key],
            "完成" if achievement_value["is_completed"] else "未完成",
        )
        for achievement_key, achievement_value in rewards_status.items()
    ]


def get_current_story():
    with open("story.json", "r", encoding="utf-8") as file:
        story = json.load(file)

    storyline_date = {
        (datetime(2023, 12, 4).date(), datetime(2023, 12, 5).date()): 1,
        (datetime(2023, 12, 6).date(), datetime(2023, 12, 7).date()): 2,
        (datetime(2023, 12, 8).date(), datetime(2023, 12, 9).date()): 3,
        (datetime(2023, 12, 10).date(), datetime(2023, 12, 11).date()): 4,
        (datetime(2023, 12, 12).date(), datetime(2023, 12, 13).date()): 5,
        (datetime(2023, 12, 14).date(), datetime(2023, 12, 15).date()): 6,
        (datetime(2023, 12, 16).date(), datetime(2023, 12, 17).date()): 7,
        (datetime(2023, 12, 18).date(), datetime(2023, 12, 19).date()): 8,
        (datetime(2023, 12, 20).date(), datetime(2023, 12, 22).date()): 9,
        (datetime(2023, 12, 23).date(), datetime(2023, 12, 25).date()): 10,
        (datetime(2023, 12, 26).date(), datetime(2023, 12, 27).date()): 11,
        (datetime(2023, 12, 28).date(), datetime(2023, 12, 29).date()): 12,
    }

    def get_stage(storyline_date):
        current_date = datetime.now().date()
        for (start_date, end_date), stage in storyline_date.items():
            if start_date <= current_date <= end_date:
                return stage
        return None

    stage = get_stage(storyline_date)

    if stage:
        return gr.Slider(
            value=stage / 12 * 100,
            show_label=False,
            interactive=False,
            info=story[str(stage)],
        )
    else:
        return gr.Slider(
            value=0,
            show_label=False,
            interactive=False,
            info="狐貍貓與光束守護者的旅程將於 2023/12/04 開始!敬請期待!",
        )


def query_bq_table(client, sql):
    try:
        query_job = client.query(sql)
        query_job.result()
        return query_job.to_dataframe()
    except Exception as e:
        logging.error(f"Query Failed: {e}")
        raise


def load_player_statuses(client):
    table_name = f"mes_report_20231229"
    sql = f"SELECT * FROM `data_mart.{table_name}`"
    return {
        row["player_backend_user_id"]: Player.from_dict(row)
        for _, row in query_bq_table(client, sql).iterrows()
    }


def save_latest_player_data():
    latest_player_data = load_player_statuses(client)
    latest_player_data_as_dict = {
        key: asdict(value) for key, value in latest_player_data.items()
    }

    def date_serializer(obj):
        if isinstance(obj, date):
            return obj.isoformat()
        raise TypeError("Type not serializable")

    with open("latest_player_data.json", "w") as fp:
        print("Saving latest player data...")
        json.dump(latest_player_data_as_dict, fp, default=date_serializer)
    return "finished"


def render_player_data(player_info: gr.State):
    player_avatar = get_player_avatar(player_info)
    player_partners = get_player_partners(player_info)
    player_badges = get_player_badges(player_info)
    player_adventure_logs = get_player_adventure_logs_html(player_info)
    player_achievements = get_player_achievements(player_info)
    current_story = get_current_story()

    return (
        player_avatar,
        player_partners,
        player_badges,
        player_adventure_logs,
        player_achievements,
        current_story,
    )


def insert_data_into_bigquery(client, dataset_id, table_id, rows_to_insert):
    # Specify the destination table
    table_ref = client.dataset(dataset_id).table(table_id)
    table = client.get_table(table_ref)

    # Insert data into the table
    errors = client.insert_rows(table, rows_to_insert)

    # Check if any errors occurred during insertion
    if errors:
        logging.info("Errors occurred while inserting rows:")
        for error in errors:
            print(error)
    else:
        logging.info(f"Inserted {len(rows_to_insert)} rows successfully.")


def render_finished(player_activity, *args):
    player_activity.render_finished(*args)
    insert_row = player_activity.to_dict()
    insert_data_into_bigquery(
        client, "streaming_log", "log_mes_player_login_activity", [insert_row]
    )
    logging.info(
        f"Player {insert_row['player_backend_user_id']} rendered successfully."
    )