data-analysis commited on
Commit
024b30f
·
verified ·
1 Parent(s): 9b40a8a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -102
app.py CHANGED
@@ -1,102 +1,102 @@
1
- import gradio as gr
2
- import pandas as pd
3
- import os
4
-
5
- # --- クラウド環境用のシンプルなパス設定 ---
6
- FILE_PATH = "VTuber_Ultimate_Database.csv"
7
- OUTPUT_DIR = "output"
8
- os.makedirs(OUTPUT_DIR, exist_ok=True)
9
-
10
- # データの読み込み
11
- try:
12
- df = pd.read_csv(FILE_PATH)
13
- unique_ids = sorted(df['ハンドル(ID)'].dropna().unique().tolist())
14
- categories = sorted(df['カテゴリ'].dropna().unique().tolist())
15
- status_msg = f"正常: {len(df)}件のレコードをデータベースから読み込みました。"
16
- except Exception as e:
17
- df = pd.DataFrame()
18
- unique_ids, categories = [], []
19
- status_msg = f"エラー: データベースが見つかりません。"
20
-
21
- # --- コアロジック ---
22
- def filter_and_export(handles, cats, keyword_in, keyword_ex, min_views, min_date, max_results):
23
- if df.empty:
24
- return None, None, "エラー: データベースが空、または未接続です。"
25
-
26
- filtered = df.copy()
27
-
28
- if handles:
29
- filtered = filtered[filtered['ハンドル(ID)'].isin(handles)]
30
- if cats:
31
- filtered = filtered[filtered['カテゴリ'].isin(cats)]
32
- if keyword_in:
33
- filtered = filtered[filtered['動画タイトル'].str.contains(keyword_in, case=False, na=False)]
34
- if keyword_ex:
35
- filtered = filtered[~filtered['動画タイトル'].str.contains(keyword_ex, case=False, na=False)]
36
-
37
- filtered = filtered[filtered['総再生数'] >= min_views]
38
- if min_date:
39
- filtered = filtered[filtered['投稿日'] >= min_date]
40
-
41
- filtered = filtered.sort_values('総再生数', ascending=False).head(max_results)
42
-
43
- txt_content = f"【VTuber市場動向 解析レポート】\n"
44
- txt_content += f"出力日時: {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
45
- txt_content += f"抽出レコード数: {len(filtered)}件\n"
46
- txt_content += "=" * 50 + "\n\n"
47
-
48
- for _, row in filtered.iterrows():
49
- txt_content += f"[{row['ハンドル(ID)']}] {row['動画タイトル']}\n"
50
- txt_content += f"カテゴリ: {row['カテゴリ']} | 総再生数: {row['総再生数']:,} | 高評価数: {row['高評価数']:,}\n"
51
- txt_content += f"投稿日: {row['投稿日']} | URL: {row['動画URL']}\n"
52
- txt_content += "-" * 50 + "\n"
53
-
54
- output_path = os.path.join(OUTPUT_DIR, "Market_Analysis_Report.txt")
55
- with open(output_path, "w", encoding="utf-8") as f:
56
- f.write(txt_content)
57
-
58
- return filtered, output_path, f"処理完了: {len(filtered)}件のデータを抽出・出力しました。"
59
-
60
- custom_css = """
61
- .gradio-container input, .gradio-container textarea, .gradio-container select {
62
- border: 1px solid #777 !important;
63
- border-radius: 4px !important;
64
- }
65
- """
66
-
67
- # --- UI構築 ---
68
- with gr.Blocks(title="VT-Analytics Pro") as app:
69
- gr.Markdown("## VTuber市場解析システム (VT-Analytics Pro)")
70
- gr.Markdown("検索条件を指定し、データ抽出およびレポート出力(txt形式)を実行してください。")
71
- gr.Markdown(f"**システムステータス:** {status_msg}")
72
-
73
- with gr.Row():
74
- with gr.Column(scale=1):
75
- in_handles = gr.Dropdown(choices=unique_ids, multiselect=True, label="対象ID指定 (複数選択可・空欄で全件)")
76
- in_cats = gr.CheckboxGroup(choices=categories, value=categories, label="コンテンツ種別")
77
- in_kw_in = gr.Textbox(placeholder="例: 歌ってみた", label="抽出キーワード (含む)")
78
- in_kw_ex = gr.Textbox(placeholder="例: 初音ミク", label="除外キーワード (含まない)")
79
-
80
- with gr.Row():
81
- in_min_views = gr.Number(value=100000, label="最低再生数")
82
- in_min_date = gr.Textbox(value="2024-01-01", label="抽出基準日 (YYYY-MM-DD以降)")
83
-
84
- in_max_res = gr.Slider(minimum=10, maximum=10000, value=1000, step=10, label="最大出力件数制限 (AI解析用)")
85
-
86
- search_btn = gr.Button("データ抽出実行", variant="primary")
87
-
88
- with gr.Column(scale=2):
89
- out_msg = gr.Textbox(label="実行ログ", interactive=False)
90
- out_file = gr.File(label="解析レポート (.txt) ダウンロード", interactive=False)
91
- out_df = gr.Dataframe(label="データプレビュー", interactive=False)
92
-
93
- search_btn.click(
94
- fn=filter_and_export,
95
- inputs=[in_handles, in_cats, in_kw_in, in_kw_ex, in_min_views, in_min_date, in_max_res],
96
- outputs=[out_df, out_file, out_msg]
97
- )
98
-
99
- if __name__ == "__main__":
100
- # 🌟 ここがパスワード設定です。Brainの購入者に教えるIDとパスワードになります。
101
- # 好きな半角英数字に変更してOKです(例では ID: user, パスワード: vtuber2026)
102
- app.launch(auth=("user", "vtuber2026"))
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import os
4
+
5
+ # --- クラウド環境用のシンプルなパス設定 ---
6
+ FILE_PATH = "VTuber_Ultimate_Database.csv"
7
+ OUTPUT_DIR = "output"
8
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
9
+
10
+ # データの読み込み
11
+ try:
12
+ df = pd.read_csv(FILE_PATH)
13
+ unique_ids = sorted(df['ハンドル(ID)'].dropna().unique().tolist())
14
+ categories = sorted(df['カテゴリ'].dropna().unique().tolist())
15
+ status_msg = f"正常: {len(df)}件のレコードをデータベースから読み込みました。"
16
+ except Exception as e:
17
+ df = pd.DataFrame()
18
+ unique_ids, categories = [], []
19
+ status_msg = f"エラー: データベースが見つかりません。"
20
+
21
+ # --- コアロジック ---
22
+ def filter_and_export(handles, cats, keyword_in, keyword_ex, min_views, min_date, max_results):
23
+ if df.empty:
24
+ return None, None, "エラー: データベースが空、または未接続です。"
25
+
26
+ filtered = df.copy()
27
+
28
+ if handles:
29
+ filtered = filtered[filtered['ハンドル(ID)'].isin(handles)]
30
+ if cats:
31
+ filtered = filtered[filtered['カテゴリ'].isin(cats)]
32
+ if keyword_in:
33
+ filtered = filtered[filtered['動画タイトル'].str.contains(keyword_in, case=False, na=False)]
34
+ if keyword_ex:
35
+ filtered = filtered[~filtered['動画タイトル'].str.contains(keyword_ex, case=False, na=False)]
36
+
37
+ filtered = filtered[filtered['総再生数'] >= min_views]
38
+ if min_date:
39
+ filtered = filtered[filtered['投稿日'] >= min_date]
40
+
41
+ filtered = filtered.sort_values('総再生数', ascending=False).head(max_results)
42
+
43
+ txt_content = f"【VTuber市場動向 解析レポート】\n"
44
+ txt_content += f"出力日時: {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
45
+ txt_content += f"抽出レコード数: {len(filtered)}件\n"
46
+ txt_content += "=" * 50 + "\n\n"
47
+
48
+ for _, row in filtered.iterrows():
49
+ txt_content += f"[{row['ハンドル(ID)']}] {row['動画タイトル']}\n"
50
+ txt_content += f"カテゴリ: {row['カテゴリ']} | 総再生数: {row['総再生数']:,} | 高評価数: {row['高評価数']:,}\n"
51
+ txt_content += f"投稿日: {row['投稿日']} | URL: {row['動画URL']}\n"
52
+ txt_content += "-" * 50 + "\n"
53
+
54
+ output_path = os.path.join(OUTPUT_DIR, "Market_Analysis_Report.txt")
55
+ with open(output_path, "w", encoding="utf-8") as f:
56
+ f.write(txt_content)
57
+
58
+ return filtered, output_path, f"処理完了: {len(filtered)}件のデータを抽出・出力しました。"
59
+
60
+ custom_css = """
61
+ .gradio-container input, .gradio-container textarea, .gradio-container select {
62
+ border: 1px solid #777 !important;
63
+ border-radius: 4px !important;
64
+ }
65
+ """
66
+
67
+ # --- UI構築 ---
68
+ with gr.Blocks(title="VT-Analytics Pro") as app:
69
+ gr.Markdown("## VTuber市場解析システム (VT-Analytics Pro)")
70
+ gr.Markdown("検索条件を指定し、データ抽出およびレポート出力(txt形式)を実行してください。")
71
+ gr.Markdown(f"**システムステータス:** {status_msg}")
72
+
73
+ with gr.Row():
74
+ with gr.Column(scale=1):
75
+ in_handles = gr.Dropdown(choices=unique_ids, multiselect=True, label="対象ID指定 (複数選択可・空欄で全件)")
76
+ in_cats = gr.CheckboxGroup(choices=categories, value=categories, label="コンテンツ種別")
77
+ in_kw_in = gr.Textbox(placeholder="例: 歌ってみた", label="抽出キーワード (含む)")
78
+ in_kw_ex = gr.Textbox(placeholder="例: 初音ミク", label="除外キーワード (含まない)")
79
+
80
+ with gr.Row():
81
+ in_min_views = gr.Number(value=100000, label="最低再生数")
82
+ in_min_date = gr.Textbox(value="2024-01-01", label="抽出基準日 (YYYY-MM-DD以降)")
83
+
84
+ in_max_res = gr.Slider(minimum=10, maximum=10000, value=1000, step=10, label="最大出力件数制限 (AI解析用)")
85
+
86
+ search_btn = gr.Button("データ抽出実行", variant="primary")
87
+
88
+ with gr.Column(scale=2):
89
+ out_msg = gr.Textbox(label="実行ログ", interactive=False)
90
+ out_file = gr.File(label="解析レポート (.txt) ダウンロード", interactive=False)
91
+ out_df = gr.Dataframe(label="データプレビュー", interactive=False)
92
+
93
+ search_btn.click(
94
+ fn=filter_and_export,
95
+ inputs=[in_handles, in_cats, in_kw_in, in_kw_ex, in_min_views, in_min_date, in_max_res],
96
+ outputs=[out_df, out_file, out_msg]
97
+ )
98
+
99
+ if __name__ == "__main__":
100
+ # 🌟 ここがパスワード設定です。Brainの購入者に教えるIDとパスワードになります。
101
+ # 好きな半角英数字に変更してOKです(例では ID: user, パスワード: vtuber2026)
102
+ app.launch(auth=("v", "0409"))