/** * WPML compatibility functions * * @global array $duplicated_posts Array to store the posts being duplicated. * * @package Yoast\WP\Duplicate_Post * @since 3.2 */ add_action( 'admin_init', 'duplicate_post_wpml_init' ); /** * Add handlers for WPML compatibility. */ function duplicate_post_wpml_init() { if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { add_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'shutdown', 'duplicate_wpml_string_packages', 11 ); } } global $duplicated_posts; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: Renaming a global variable is a BC break. $duplicated_posts = []; /** * Copy post translations. * * @global SitePress $sitepress Instance of the Main WPML class. * @global array $duplicated_posts Array of duplicated posts. * * @param int $post_id ID of the copy. * @param WP_Post $post Original post object. * @param string $status Status of the new post. */ function duplicate_post_wpml_copy_translations( $post_id, $post, $status = '' ) { global $sitepress; global $duplicated_posts; remove_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10 ); remove_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10 ); $current_language = $sitepress->get_current_language(); $trid = $sitepress->get_element_trid( $post->ID ); if ( ! empty( $trid ) ) { $translations = $sitepress->get_element_translations( $trid ); $new_trid = $sitepress->get_element_trid( $post_id ); foreach ( $translations as $code => $details ) { if ( $code !== $current_language ) { if ( $details->element_id ) { $translation = get_post( $details->element_id ); if ( ! $translation ) { continue; } $new_post_id = duplicate_post_create_duplicate( $translation, $status ); if ( ! is_wp_error( $new_post_id ) ) { $sitepress->set_element_language_details( $new_post_id, 'post_' . $translation->post_type, $new_trid, $code, $current_language ); } } } } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: see above. $duplicated_posts[ $post->ID ] = $post_id; } } /** * Duplicate string packages. * * @global array() $duplicated_posts Array of duplicated posts. */ function duplicate_wpml_string_packages() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: renaming the function would be a BC-break. global $duplicated_posts; foreach ( $duplicated_posts as $original_post_id => $duplicate_post_id ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $original_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $original_post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $new_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $duplicate_post_id ); if ( is_array( $original_string_packages ) ) { foreach ( $original_string_packages as $original_string_package ) { $translated_original_strings = $original_string_package->get_translated_strings( [] ); foreach ( $new_string_packages as $new_string_package ) { $cache = new WPML_WP_Cache( 'WPML_Package' ); $cache->flush_group_cache(); $new_strings = $new_string_package->get_package_strings(); foreach ( $new_strings as $new_string ) { if ( isset( $translated_original_strings[ $new_string->name ] ) ) { foreach ( $translated_original_strings[ $new_string->name ] as $language => $translated_string ) { do_action( // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. 'wpml_add_string_translation', $new_string->id, $language, $translated_string['value'], $translated_string['status'] ); } } } } } } } } 工程4以降の変更 – Raqqa

工程4以降の変更

工程4(改訂):外部連携I/Fの確定(接続なしでOK)

目的

nlq-dev が「SQL/Cypher文字列を作らず params を渡す」前提で、外部I/F(リクエスト/レスポンスの形)を固定する。
dev-portal / DeciKG が存在しなくても、Stubで開発を進められる状態にする。

4-A) Dev-Portal 側(SqlExecutor)—接続なし版

方針

  • nlq-dev → Dev-Portal に渡すのは SQLではなく sql_params
  • ただし dev-portal未接続の間は Stub が tabular_result を返す
  • 後から実dev-portalに差し替えても nlq-dev の上位(router/UI)が変わらない形にする

追加/変更ファイル(nlq-dev側)

  • services/dev_portal_client.py
    • health() -> HealthResult
    • execute_sql_params(sql_params, max_rows, dry_run) -> TabularResult
  • services/dev_portal_client_stub.py(または同ファイル内で mode 切替)
    • 固定のダミー結果を返す
  • schemas/dev_portal.py
    • TabularResult, HealthResult, Problem(最低限)

DoD(接続なし)

  • DEVPORTAL_MODE=dummy|http を導入
  • dummy のとき:
    • health() が常に “OK” を返す(HTTP不要)
    • execute_sql_params()決め打ちの表を返す(例:売上の月次集計サンプル)
  • http のとき(将来):
    • 実dev-portalへ接続して同じ型で返る

✅ これで「I/F固定」と「開発を止めない」を同時に満たします。


4-B) DeciKG 側(CypherExecutor)—接続なし版

方針

  • nlq-dev → DeciKG に渡すのは Cypherではなく decikg_params
  • DeciKG未接続の間は Stub が graph_result を返す
  • 後から Aura に差し替えても nlq-dev の上位が変わらない形

追加/変更ファイル(nlq-dev側)

  • services/decikg_client.py
    • health() -> HealthResult
    • query(decikg_params) -> GraphResult
    • concept_lookup(text) -> Candidates(必要なら)
  • services/decikg_client_stub.py
  • schemas/graph_result.py(GraphResultの型)
  • schemas/decikg.py(params/candidates型)

DoD(接続なし)

  • DECIGK_MODE=dummy|http
  • dummy のとき:
    • health() がOKを返す
    • query()固定のnode/edge/evidence を返す(例:KPI低下→材料費増→仕入単価上昇)
  • http のとき(将来):
    • Aura/DeciKG APIへ接続して同じ型で返る

工程5(改訂):Executeレスポンス拡張(接続なしでOK)

目的

SQLだけ前提をやめ、SQL結果・Graph結果・統合結果を同じレスポンスで返せるようにする。
接続がなくても「Stub結果でUI/分析を作り込める」ようにする。

方針(互換維持)

  • 既存の ExecuteResponse.columns/rows/sql は残す
  • 追加:
    • execution_kind(sql|graph|hybrid|stub 等)
    • route(SQL_ONLY/CYPHER_ONLY/CYPHER_THEN_SQL 等)
    • graph(GraphResult)
    • merged(MergeResult:統合要約)
    • narration(説明文)

DoD(接続なし)

  • DEVPORTAL_MODE=dummy の場合:SQL結果が返る(従来互換)
  • DECIGK_MODE=dummy の場合:graph結果が返る(columns/rowsは空でもOK)
  • hybrid の場合:mergedに統合要約が入る(固定テンプレでもOK)

工程6(改訂):履歴と成果物の拡張(接続なしでOK)

目的

あとから改善できるように、route/params/外部結果/失敗を追跡可能にする。
接続がなくても「Stub呼び出しとして記録」できる。

変更点(最小)

  • historyに必ず保存:
    • route
    • sql_params, decikg_params
    • execution_kind
    • providers: devportal(dummy/http), decikg(dummy/http)
    • timings_ms(dummyでも計測)
    • error_summary(失敗時)

DoD(接続なし)

  • /nlq/history で route と execution_kind が追える
  • “なぜDeciKGになったか” の説明をメモとして残せる
    • dummyでも「候補一覧」「選択理由」を保存(固定文でもOK)

工程7(改訂):ドキュメント更新(接続なしでOK)

目的

オフショア/フロントが迷わない “固定文書” を揃える。
接続がなくても、**I/Fと切替方法(dummy→http)**が明確なら前に進める。

追加するべき文書(特に重要)

  • docs/NLQ_API_CONTRACT.md
    • ExecuteResponse v0.2(sql/graph/merged/narration)を固定
  • docs/dev-portal-integration.md
    • DEVPORTAL_MODE/sql/execute_params のYAML参照先
  • docs/decikg-integration.md
    • DECIGK_MODEdecikg_params/graph_resultの例
  • README
    • ローカル起動(dummyモード)でUI/analysisまで動く手順

DoD(接続なし)

  • 「nlq-devはSQL/Cypher文字列を作らない」が明文化
  • 「会社差分(Mermaid/辞書等)をどこで更新するか」が明確
  • dummyモードの起動だけで、分析画面まで動く

まとめ:接続なし開発にするための“決定事項”の核

  • 外部I/Fは 先にYAML/Schemaで固定
  • 実体がなくても *_MODE=dummy同じ型の結果を返す
  • nlq-dev の上位(routers/UI/analysis/history)は 外部の有無で分岐しない
  • 後から dummy -> http に切り替えるだけで疎通に進める

必要なら、この改訂版をそのまま 「工程4〜7 決定事項(v0.2)」のMarkdownに整形して、docs配下に置く前提の文章(コピペ用)まで一気に作ります。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です