terapyon commited on
Commit
d788666
·
1 Parent(s): 608103a

srtの分割を1分にし、configなどを整え、READMEを書いた

Browse files
Files changed (4) hide show
  1. README.md +135 -0
  2. src/config.py +8 -0
  3. src/episode.py +8 -13
  4. src/store.py +4 -8
README.md CHANGED
@@ -3,3 +3,138 @@
3
  Podcast terapyon channelを検索する仕組み
4
 
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  Podcast terapyon channelを検索する仕組み
4
 
5
 
6
+ ## 使い方
7
+
8
+
9
+ ### タイトルリスト
10
+
11
+ - 以下のファイルを`store` フォルダに置く
12
+ - `title-list-202301-202501.parquet`
13
+ - 以下のカラムを持つ
14
+ - id: int
15
+ - date: str (2023-01-09)
16
+ - length: int
17
+ - audio: str (オーディオファイルURL)
18
+ - title: str
19
+
20
+ タイトルリストファイルの例
21
+
22
+ <div>
23
+ <style scoped>
24
+ .dataframe tbody tr th:only-of-type {
25
+ vertical-align: middle;
26
+ }
27
+
28
+ .dataframe tbody tr th {
29
+ vertical-align: top;
30
+ }
31
+
32
+ .dataframe thead th {
33
+ text-align: right;
34
+ }
35
+ </style>
36
+ <table border="1" class="dataframe">
37
+ <thead>
38
+ <tr style="text-align: right;">
39
+ <th></th>
40
+ <th>id</th>
41
+ <th>date</th>
42
+ <th>length</th>
43
+ <th>audio</th>
44
+ <th>title</th>
45
+ </tr>
46
+ </thead>
47
+ <tbody>
48
+ <tr>
49
+ <th>0</th>
50
+ <td>69</td>
51
+ <td>2023-01-09</td>
52
+ <td>20993616</td>
53
+ <td>https://anchor.fm/s/14480e04/podcast/play/6323...</td>
54
+ <td>#69 2023年新年挨拶から 2022年の振り返りと2023年の抱負</td>
55
+ </tr>
56
+ <tr>
57
+ <th>1</th>
58
+ <td>70</td>
59
+ <td>2023-03-09</td>
60
+ <td>103287296</td>
61
+ <td>https://anchor.fm/s/14480e04/podcast/play/6621...</td>
62
+ <td>#70 PyCon JP Association代表理事退任と今後の展望をIqbalさんと語る</td>
63
+ </tr>
64
+ <tr>
65
+ <th>2</th>
66
+ <td>71</td>
67
+ <td>2023-03-22</td>
68
+ <td>116393694</td>
69
+ <td>https://anchor.fm/s/14480e04/podcast/play/6706...</td>
70
+ <td>#71 hirokikyさんをゲストに 自然言語処理系AI Chat GPT / Whisp...</td>
71
+ </tr>
72
+ <tr>
73
+ <th>3</th>
74
+ <td>72</td>
75
+ <td>2023-05-04</td>
76
+ <td>49642320</td>
77
+ <td>https://anchor.fm/s/14480e04/podcast/play/6976...</td>
78
+ <td>#72 PyCon US 2023 ひとり振り返り</td>
79
+ </tr>
80
+ <tr>
81
+ <th>4</th>
82
+ <td>73</td>
83
+ <td>2023-05-24</td>
84
+ <td>150643013</td>
85
+ <td>https://anchor.fm/s/14480e04/podcast/play/7094...</td>
86
+ <td>#73 Nyohoさんをゲストに Scratchからディープラーニングや数学の話</td>
87
+ </tr>
88
+ </tbody>
89
+ </table>
90
+ </div>
91
+
92
+ ### 文字データ作成
93
+
94
+ - dataフォルダをを作る(srcと同じ階層)
95
+ - dataフォルダに、srtファイルを入れる
96
+ - (以下に従うと、srtファイルからIDが取得できる)
97
+ - 拡張子を `.srt` とする
98
+ - ファイル名に、ID(整数)が1つだけ入ってること
99
+ - IDの前後に、 `-` または `_` で区切られいること
100
+ - 以下のスクリプトを実行する。 `store` フォルダに `parquet` ファイルが srtファイル分できる
101
+
102
+ ```
103
+ % python src/episode.py
104
+ ```
105
+
106
+ ### データベース作成
107
+
108
+ 以下のコマンドで、テーブル作成から必要な3つのデータをDuckDB(永続化)を作る
109
+
110
+ ```
111
+ % python src/store.py all
112
+ ```
113
+
114
+ 上記のコマンドの詳細
115
+
116
+ - テーブル作成 create table
117
+ - `python src/store.py create`
118
+ - タイトルリスト insert
119
+ - `python src/store.py podcastinsert`
120
+ - エピソードとテキスト insert
121
+ - `python src/store.py episodeinsert`
122
+ - ベクトル化 embedding
123
+ - `python src/store.py embed`
124
+ - ベクトルデータ index
125
+ - `python src/store.py index`
126
+
127
+
128
+ ### 検索UI
129
+
130
+ ```
131
+ % streamlit run src/app.py
132
+ ```
133
+
134
+ - Podcastタイトル(複数)を選ぶ。未選択の場合すべてとなる
135
+ - 検索したいワードをテキストボックスに入力
136
+ - 10個のセンテンス(文章)候補が出てくる
137
+ - 表の左をクリックすると、下部に文字列が表示される
138
+ - 音声のタイミング(分・秒)が表示される・・未実装
139
+ - そのタイミングの音声がその場で聞ける・・将来的に実装したいが実現方法未確定
140
+
src/config.py CHANGED
@@ -1,6 +1,14 @@
 
 
1
  from pathlib import Path
2
  # import logging
3
 
4
 
5
  HERE = Path(__file__).resolve().parent
6
  DUCKDB_FILE = HERE.parent / "db" / "terapyon-podcast.duckdb"
 
 
 
 
 
 
 
1
+ from datetime import timedelta
2
+ import re
3
  from pathlib import Path
4
  # import logging
5
 
6
 
7
  HERE = Path(__file__).resolve().parent
8
  DUCKDB_FILE = HERE.parent / "db" / "terapyon-podcast.duckdb"
9
+ STORE_DIR = HERE.parent / "store"
10
+ DATA_DIR = HERE.parent / "data"
11
+ PODCAST_TITLE_LIST = str(STORE_DIR / 'title-list-202301-202501.parquet')
12
+ EPISODES_PARQUET = str(STORE_DIR / 'podcast-*.parquet')
13
+ divider_time = timedelta(minutes=1)
14
+ RE_PODCAST_SRT_FILE = re.compile(r"[_-](\d+)[_-]")
src/episode.py CHANGED
@@ -1,23 +1,15 @@
1
  from dataclasses import dataclass
2
  from datetime import time as dt_time
3
  from datetime import timedelta
4
- from pathlib import Path
5
- import re
6
  import pandas as pd
7
-
8
-
9
- HERE = Path(__file__).parent
10
- DATA_DIR = HERE.parent / "data"
11
- STORE_DIR = HERE.parent / "store"
12
- divider_time = timedelta(minutes=5)
13
- RE_PODCAST = re.compile(r"[_-](\d+)[_-]")
14
 
15
 
16
  @dataclass
17
  class SplitedText:
18
  part: int
19
- start: timedelta
20
- end: timedelta
21
  text: str
22
 
23
 
@@ -72,7 +64,10 @@ def make_episode(id_: int, title: str, srt_filename: str) -> Episode:
72
  if start and second and text:
73
  if abs(second - start) > divider_time:
74
  end = second
75
- st = SplitedText(part=part, start=start, end=end, text=text)
 
 
 
76
  episode.texts.append(st)
77
 
78
  # print(text)
@@ -95,7 +90,7 @@ def make_df(episode: Episode) -> pd.DataFrame:
95
  def get_srt_files():
96
  lst = []
97
  for file_path in DATA_DIR.glob("*.srt"):
98
- m = RE_PODCAST.search(file_path.name)
99
  if m is not None:
100
  filename = file_path.name
101
  id_ = int(m.group(1))
 
1
  from dataclasses import dataclass
2
  from datetime import time as dt_time
3
  from datetime import timedelta
 
 
4
  import pandas as pd
5
+ from config import STORE_DIR, DATA_DIR, divider_time, RE_PODCAST_SRT_FILE
 
 
 
 
 
 
6
 
7
 
8
  @dataclass
9
  class SplitedText:
10
  part: int
11
+ start: int
12
+ end: int
13
  text: str
14
 
15
 
 
64
  if start and second and text:
65
  if abs(second - start) > divider_time:
66
  end = second
67
+ st = SplitedText(part=part,
68
+ start=int(start.total_seconds()),
69
+ end=int(end.total_seconds()),
70
+ text=text)
71
  episode.texts.append(st)
72
 
73
  # print(text)
 
90
  def get_srt_files():
91
  lst = []
92
  for file_path in DATA_DIR.glob("*.srt"):
93
+ m = RE_PODCAST_SRT_FILE.search(file_path.name)
94
  if m is not None:
95
  filename = file_path.name
96
  id_ = int(m.group(1))
src/store.py CHANGED
@@ -1,17 +1,13 @@
1
- from pathlib import Path
2
  import duckdb
3
  from embedding import get_embeddings
4
  from config import DUCKDB_FILE
5
-
6
-
7
- HERE = Path(__file__).parent
8
- STORE_DIR = HERE.parent / "store"
9
 
10
 
11
  def create_table():
12
  conn = duckdb.connect(DUCKDB_FILE)
13
  podcasts_create = """CREATE TABLE podcasts (
14
- id BIGINT PRIMARY KEY,
15
  title TEXT, date DATE, guests TEXT[], length BIGINT, audio TEXT
16
  );
17
  """
@@ -39,7 +35,7 @@ def insert_podcast():
39
  SELECT id, title, date, [], length, audio
40
  FROM read_parquet(?);
41
  """
42
- conn.execute(sql, [str(STORE_DIR / 'title-list-202301-202501.parquet')])
43
  conn.commit()
44
  conn.close()
45
 
@@ -50,7 +46,7 @@ def insert_episodes():
50
  SELECT id, part, start, end_, text
51
  FROM read_parquet(?);
52
  """
53
- conn.execute(sql, [str(STORE_DIR / 'podcast-*.parquet')])
54
  conn.commit()
55
  conn.close()
56
 
 
 
1
  import duckdb
2
  from embedding import get_embeddings
3
  from config import DUCKDB_FILE
4
+ from config import PODCAST_TITLE_LIST, EPISODES_PARQUET
 
 
 
5
 
6
 
7
  def create_table():
8
  conn = duckdb.connect(DUCKDB_FILE)
9
  podcasts_create = """CREATE TABLE podcasts (
10
+ id BIGINT PRIMARY KEY,
11
  title TEXT, date DATE, guests TEXT[], length BIGINT, audio TEXT
12
  );
13
  """
 
35
  SELECT id, title, date, [], length, audio
36
  FROM read_parquet(?);
37
  """
38
+ conn.execute(sql, [PODCAST_TITLE_LIST])
39
  conn.commit()
40
  conn.close()
41
 
 
46
  SELECT id, part, start, end_, text
47
  FROM read_parquet(?);
48
  """
49
+ conn.execute(sql, [EPISODES_PARQUET])
50
  conn.commit()
51
  conn.close()
52