ken_nogi/lineworks-sync/csv-anythingllm.spec.md
Kenichiro NOGI 88a402ce0f up
2026-07-10 18:13:30 +09:00

12 KiB

csv-anythingllm.js 仕様書

1. 概要

originalData/ フォルダに置いた Excel ファイル(顧客相談履歴など)を、シート単位で CSV に分割し、各シートに紐づく AnythingLLM ワークスペースへ RAG 用ドキュメントとして登録するスクリプト。

LINE WORKS 掲示板を扱う lineworks-anythingllm.js とは独立しており、AnythingLLM への実際のアップロード/embedding 処理は共通モジュール anythingllm-client.js を利用する。

2. 実行環境・依存パッケージ

  • Node.js 18 以上(標準 fetch を使用)
  • 依存パッケージ: xlsx(Excel/CSV の読み書き)
  • 実行例: node csv-anythingllm.js <コマンド>
  • ダブルクリック実行用: run-csv-sync-all.bat(sync-all を実行して自動終了)

3. コマンド一覧

コマンド 内容
node csv-anythingllm.js convert originalData/ 内の全 .xlsx を読み込み、シートごとに CSV へ変換。シート別の設定ファイル雛形と csv-list.csv への自動登録も行う。
node csv-anythingllm.js sync <シート名> 指定した1シートのみ同期する(csv-list.csv のフラグに関係なく常に実行される)。
node csv-anythingllm.js sync-all csv-list.csvflag=1 になっているシートのみ、順番に同期する。

引数無し、または上記以外のコマンドの場合は使い方メッセージを表示して終了する。

4. 環境変数

変数名 既定値 用途
ANYTHINGLLM_BASE_URL (必須) AnythingLLM の URL。lineworks-anythingllm.js と共通。
ANYTHINGLLM_API_KEY (必須) AnythingLLM の API キー。
EMBEDDING_BATCH_SIZE 50 embedding 登録リクエストのバッチサイズ。
ORIGINAL_DATA_DIR ./originalData 変換元 Excel の配置フォルダ。
CSV_ROOT_DIR ./csv シート別 CSV の出力先ルート。
CSV_CONFIG_DIR ./csv-config シート別設定ファイル・重複防止ハッシュの保存先。
CSV_CHUNK_MAX_LENGTH 2000 相談履歴を分割するチャンクの目安文字数。
CSV_LOG_DIR ./logs 実行ログの保存先。

csv-list.csv の配置パスは環境変数化されておらず、常にスクリプトと同じフォルダ(csv-list.csv)固定。

5. ディレクトリ・ファイル構成

originalData/                 変換元の Excel ファイル(.xlsx)を置く場所
originalData/complete/        convert で変換完了したExcelの退避先(5.1節)
csv/<シート名>/                convert で生成されるシート別 CSV
csv/<シート名>/complete/       sync で全行処理完了したCSVの退避先(5.1節)
csv-config/<シート名>.json     シート別設定(csvDir, workspaceSlug)
csv-config/<シート名>.uploaded-hashes.json  重複防止用のアップロード済みハッシュ一覧
csv_chunks_md/<シート名>/      sync 実行時に生成される、行ごとのチャンク Markdown
csv_chunks_md/<シート名>/complete/  sync でアップロード成功したチャンクMDの退避先(5.1節)
csv-list.csv                  sync-all の同期対象を管理するマスターリスト(必須)
logs/csv-anythingllm_<コマンド>_<日時>.log  実行ログ

5.1 取り込み完了ファイルの退避(complete フォルダ)

処理が完了したファイルは、元のディレクトリ配下の complete/ サブフォルダへ移動し、次回実行時の対象から除外する(fs.readdirSync は非再帰的なため、complete/ 配下は自動的に再変換・再アップロード対象から外れる)。共通関数 moveFileToCompleteDir で移動する。

対象 移動タイミング 移動先
originalData/*.xlsx convert でそのExcelの全シート変換が完了した直後 originalData/complete/
csv/<シート名>/*.csv sync(syncSheet)でそのCSVの全行を処理し終えた直後(新規アップロード/重複スキップ問わず) csv/<シート名>/complete/
csv_chunks_md/<シート名>/*.md sync でチャンクMDファイルのアップロードが成功した直後 csv_chunks_md/<シート名>/complete/
  • 同名ファイルが移動先に既に存在する場合は上書きせず、<ファイル名>_<タイムスタンプ>.<拡張子> の形式で退避する。
  • convert 実行中に1ファイルの移動に失敗しても、警告ログを出力するのみで他のファイルの処理は継続する。
  • CSVファイルの移動は行のアップロード成否とは独立して、行ループが例外なく完了した時点で行われる(embedding登録バッチが一部失敗しても、既にアップロード済みの行のハッシュ記録自体はそのまま有効という既存の重複防止の考え方に合わせている)。

6. 処理フロー

6.1 convert

  1. ORIGINAL_DATA_DIR 内の .xlsx を1つずつ読み込む。
  2. 各シートについて sheet_to_csv で CSV テキストを生成し、CSV_ROOT_DIR/<安全化したシート名>/<シート名>__<Excelファイル名>.csv として UTF-8(BOM付き)で出力する。
  3. シート別設定ファイル csv-config/<シート名>.json が存在しない場合のみ、{ "csvDir": "csv/<シート名>", "workspaceSlug": "" } の雛形を新規作成する(既存ファイルは上書きしない)。
  4. csv-list.csv にそのシート名が未登録の場合、flag=0 で追記登録する(既存行・既存 flag は変更しない)。手動で日本語のシート名を入力する手間とタイプミスを防ぐための自動登録。
  5. そのExcelファイルの全シートの変換が終わったら、originalData/complete/ へ移動する(5.1節)。

6.2 sync <シート名>(syncSheet 関数)

  1. csv-config/<シート名>.json を読み込む。存在しない場合はエラー(convert を先に実行するよう促す)。
  2. workspaceSlug が未設定ならエラー。
  3. ensureWorkspaceExists で AnythingLLM 側に同名(name または slug 一致)のワークスペースが存在するか確認。無ければ自動作成し、実際に採番された slug を設定ファイルへ書き戻す。
  4. csvDir 配下の全 .csv を読み込み、1行ごとに以下を処理:
    • 1列目=顧客名、2列目=日付、3列目=相談履歴(位置ベースで読む。ヘッダー行はスキップ)。
    • 顧客名・相談履歴が両方空の行はスキップ。
    • 顧客名+日付+相談履歴の全文から SHA-256 ハッシュを計算し、csv-config/<シート名>.uploaded-hashes.json に既に記録済みならスキップ(重複防止、詳細は 7.3 節)。
    • 未登録の行は「発言」単位でチャンク分割し(7.2 節)、チャンクごとに Markdown ファイル(csv_chunks_md/<シート名>/ 配下)を生成して AnythingLLM にアップロード(uploadFile)。
    • アップロード後、ハッシュを記録済み一覧へ追加してファイルへ即時保存する(途中で異常終了しても再実行時に重複しないようにするため)。アップロードに成功したチャンクMDファイルは csv_chunks_md/<シート名>/complete/ へ移動する(5.1節)。
    • 1つのCSVファイルの全行を処理し終えたら、そのCSVファイル自体も csv/<シート名>/complete/ へ移動する(5.1節)。
  5. 新規アップロードされたドキュメントの location をまとめて、addToWorkspaceEmbeddings でワークスペースへ embedding 登録する(EMBEDDING_BATCH_SIZE 件ずつバッチ処理)。
  6. 最後に「新規アップロード件数 / スキップ(重複)件数」をログ出力する。

6.3 sync-all

  1. CSV_CONFIG_DIR が存在しなければエラーメッセージを出して終了。
  2. csv-list.csv を読み込み、flag 列が "1" の行のシート名一覧を取得する(loadTargetSheetsFromCsv)。
  3. 対象が0件の場合(ファイルが無い場合を含む)は「何も同期せず終了します」とログ出力して終了する。全件同期へのフォールバックは行わない(lineworks-anythingllm.jsboard-list.csv とはこの点が異なる)。
  4. 対象シートを1件ずつ syncSheet で同期する。1シートの同期に失敗しても、エラーをログ出力して次のシートの処理を継続する。

7. データ形式

7.1 csv-config/<シート名>.json

{ "csvDir": "csv/<シート名>", "workspaceSlug": "アップロード先ワークスペースのslug" }
  • csvDir: シート別 CSV の格納フォルダ(相対パスは __dirname 基準)。
  • workspaceSlug: 空文字の場合はエラーになるため、convert 実行後に手動で入力する。存在しないワークスペース名を指定した場合は sync 実行時に自動作成され、実際の slug に書き換わる。

7.2 csv-config/<シート名>.uploaded-hashes.json

アップロード済み行のハッシュ文字列を格納した JSON 配列。

7.3 csv-list.csv(sync-all のマスターリスト)

sheetName,flag
800300000001333_bot_人事・採用・労務窓口,0
980300000003132_line_oa_ネクストホール,1
  • 1列目 sheetName: csv-config/<シート名>.json のファイル名(拡張子除く)と一致させる。
  • 2列目 flag: "1" の行だけが sync-all の対象。それ以外(0 や空)は対象外。
  • カンマ区切りの単純なパース(split(","))であり、CSV のクォート/エスケープには対応していない。シート名にカンマを含めないこと。

7.4 変換後 CSV の列構成

位置ベースで読む: 1列目=顧客名、2列目=日付、3列目=相談履歴。

8. チャンク分割ロジック

  • 相談履歴は「名前:コメント」または「名前:コメント」形式の発言が連続する想定。行頭がこのパターンに一致する行を新しい発言の開始とみなす(TURN_START_PATTERN)。ただし https:// のような URL 行頭は誤検出しないよう除外。
  • 発言を先頭から貪欲に積み上げ、次の発言を足すと CSV_CHUNK_MAX_LENGTH(既定2000文字)を超える場合にチャンクを区切る。
  • 1発言自体が上限を超える場合は、発言の途中では切らずそのまま単独チャンクとする。

9. 重複防止の仕組み

顧客名 + "|" + 日付 + "|" + 相談履歴 の全文から SHA-256 ハッシュを生成し、シートごとの uploaded-hashes.json に記録する。originalData の Excel は毎回過去分すべてを含む想定のため、日次実行しても既にアップロード済みの行が重複登録されない。

10. ログ出力

logs/csv-anythingllm_<コマンド>_<実行日時>.log に、コンソール出力(console.log/warn/error)を [YYYY-MM-DD HH:mm:ss] [INFO|WARN|ERROR] メッセージ の形式で1行ずつ追記する。異常終了してもそこまでの実行内容が残る。

11. 制限事項・注意点

  • sync-allcsv-list.csv が無い、または flag=1 の行が無い場合、何も同期しない(自動フォールバックしない仕様)。同期したいシートは必ず手動で flag1 にする必要がある。
  • sync <シート名> はフラグを一切参照しないため、csv-list.csv の設定に関わらず常に実行される。
  • csv-list.csv / 各種設定ファイルのシート名はカンマを含めないこと(単純な split(",") によるパースのため)。
  • ワークスペースの自動作成・自動 slug 反映は sync(および sync-all 経由の syncSheet)実行時のみ行われる。
  • originalData/csv/<シート名>/csv_chunks_md/<シート名>complete/ サブフォルダはそれぞれ非再帰リストの対象外として扱われる前提の仕組みのため、complete/ を手動でリネームしてスキャン対象の階層に置いてしまうと再変換・再アップロードされる点に注意。

12. 関連ファイル