| #!/usr/bin/env bun |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { createClient } from '@supabase/supabase-js' |
| import { writeFile } from 'node:fs/promises' |
| import { resolve } from 'node:path' |
|
|
| |
| interface MethodologyVector { |
| id: string |
| methodology_code: string |
| registry: string |
| name_ko: string |
| name_en: string |
| applicability: string |
| emission_factors: Record<string, unknown> |
| required_params: string[] |
| embedding?: number[] | null |
| created_at: string |
| updated_at: string |
| } |
|
|
| interface ExportRow { |
| id: string |
| methodology_code: string |
| registry: string |
| name_ko: string |
| name_en: string |
| applicability: string |
| emission_factors_json: string |
| required_params: string |
| embedding_dim?: number |
| created_at: string |
| updated_at: string |
| } |
|
|
| |
| const args = process.argv.slice(2) |
| const outputPath = (() => { |
| const idx = args.indexOf('--output') |
| return idx !== -1 ? args[idx + 1] : `methodology-vectors-${new Date().toISOString().slice(0, 10)}.csv` |
| })() |
| const format = (() => { |
| const idx = args.indexOf('--format') |
| return idx !== -1 ? args[idx + 1] : 'csv' |
| })() as 'csv' | 'json' |
| const includeEmbedding = args.includes('--include-embedding') |
|
|
| |
| const supabaseUrl = process.env.SUPABASE_URL |
| const supabaseKey = process.env.SUPABASE_SERVICE_KEY ?? process.env.SUPABASE_ANON_KEY |
|
|
| if (!supabaseUrl || !supabaseKey) { |
| console.error( |
| 'ERROR: SUPABASE_URL λ° SUPABASE_ANON_KEY (λλ SUPABASE_SERVICE_KEY)λ₯Ό νκ²½ λ³μλ‘ μ€μ νμΈμ.' |
| ) |
| console.error(' export SUPABASE_URL=https://your-project.supabase.co') |
| console.error(' export SUPABASE_ANON_KEY=your-anon-key') |
| process.exit(1) |
| } |
|
|
| const supabase = createClient(supabaseUrl, supabaseKey) |
|
|
| |
| async function fetchMethodologyVectors(): Promise<MethodologyVector[]> { |
| const select = includeEmbedding |
| ? '*' |
| : 'id, methodology_code, registry, name_ko, name_en, applicability, emission_factors, required_params, created_at, updated_at' |
|
|
| const { data, error } = await supabase |
| .from('methodology_vectors') |
| .select(select) |
| .order('registry', { ascending: true }) |
| .order('methodology_code', { ascending: true }) |
|
|
| if (error) { |
| throw new Error(`Supabase μ‘°ν μ€ν¨: ${error.message}`) |
| } |
|
|
| return (data ?? []) as unknown as MethodologyVector[] |
| } |
|
|
| |
| function toCsvRow(row: ExportRow): string { |
| const fields = [ |
| row.id, |
| row.methodology_code, |
| row.registry, |
| row.name_ko, |
| row.name_en, |
| row.applicability.replace(/"/g, '""'), |
| row.emission_factors_json.replace(/"/g, '""'), |
| row.required_params, |
| includeEmbedding ? String(row.embedding_dim ?? '') : '', |
| row.created_at, |
| row.updated_at, |
| ] |
| return fields.map((f) => `"${f}"`).join(',') |
| } |
|
|
| function buildCsvHeader(): string { |
| const cols = [ |
| 'id', |
| 'methodology_code', |
| 'registry', |
| 'name_ko', |
| 'name_en', |
| 'applicability', |
| 'emission_factors_json', |
| 'required_params', |
| ...(includeEmbedding ? ['embedding_dimensions'] : []), |
| 'created_at', |
| 'updated_at', |
| ] |
| return cols.join(',') |
| } |
|
|
| |
| async function main() { |
| console.log('methodology_vectors ν
μ΄λΈ λ΄λ³΄λ΄κΈ° μμ...') |
| console.log(` Supabase URL: ${supabaseUrl}`) |
| console.log(` μΆλ ₯ νμ: ${format}`) |
| console.log(` μΆλ ₯ κ²½λ‘: ${resolve(outputPath)}`) |
| console.log(` μλ² λ© ν¬ν¨: ${includeEmbedding}`) |
| console.log() |
|
|
| let rows: MethodologyVector[] |
| try { |
| rows = await fetchMethodologyVectors() |
| } catch (err) { |
| console.error('λ°μ΄ν° μ‘°ν μ€ν¨:', err) |
| process.exit(1) |
| } |
|
|
| console.log(` μ‘°νλ λ°©λ²λ‘ μ: ${rows.length}건`) |
|
|
| |
| const exportRows: ExportRow[] = rows.map((r) => ({ |
| id: r.id, |
| methodology_code: r.methodology_code, |
| registry: r.registry, |
| name_ko: r.name_ko, |
| name_en: r.name_en, |
| applicability: r.applicability, |
| emission_factors_json: JSON.stringify(r.emission_factors), |
| required_params: (r.required_params ?? []).join(';'), |
| embedding_dim: Array.isArray(r.embedding) ? r.embedding.length : undefined, |
| created_at: r.created_at, |
| updated_at: r.updated_at, |
| })) |
|
|
| let output: string |
| if (format === 'json') { |
| output = JSON.stringify( |
| rows.map((r) => ({ |
| ...r, |
| embedding: includeEmbedding ? r.embedding : `<${Array.isArray(r.embedding) ? r.embedding.length : 0}-dim vector omitted>`, |
| })), |
| null, |
| 2 |
| ) |
| } else { |
| |
| const lines = [buildCsvHeader(), ...exportRows.map(toCsvRow)] |
| output = lines.join('\n') |
| } |
|
|
| const absPath = resolve(outputPath) |
| try { |
| await writeFile(absPath, output, 'utf-8') |
| } catch (err) { |
| console.error('νμΌ μ°κΈ° μ€ν¨:', err) |
| process.exit(1) |
| } |
|
|
| console.log(`\nλ΄λ³΄λ΄κΈ° μλ£: ${absPath}`) |
| console.log() |
| console.log('λ°©λ²λ‘ μ½λ λͺ©λ‘:') |
| for (const r of exportRows) { |
| console.log(` [${r.registry.padEnd(14)}] ${r.methodology_code.padEnd(20)} β ${r.name_ko}`) |
| } |
|
|
| console.log() |
| console.log('μΈλΆ κ²μ¦μΈ μ¬μ© μ§μΉ¨:') |
| console.log(' 1. emission_factors_json: λ°©λ²λ‘ λ³ λ°°μΆκ³μ κΈ°λ³Έκ° νμΈ') |
| console.log(' 2. required_params: ν΄λΉ λ°©λ²λ‘ μ νμν λͺ¨λν°λ§ λ³μ λͺ©λ‘ (μΈλ―Έμ½λ‘ ꡬλΆ)') |
| console.log(' 3. μλ² λ©(--include-embedding): νλ‘λμ
μ¬μλ ν OpenAI μ€μ 벑ν°λ‘ κ΅μ²΄ νμ') |
| console.log(' 4. λ°©λ²λ‘ μμΈ: docs/methodology/ λλ ν°λ¦¬ μ°Έμ‘°') |
| } |
|
|
| main().catch((err) => { |
| console.error('μκΈ°μΉ μμ μ€λ₯:', err) |
| process.exit(1) |
| }) |
|
|