Appearance
OpenAI APIでRAGのやり方
AIとかにIDやファイルパスを教えて以下のコードに当てはめて的な指示すれば一発だと思います。
この手順では 各自の環境に合わせて値を設定してください。
角括弧
<>のプレースホルダは必ず自分の値に置き換えること。
置換ルール(必読)
<VECTOR_STORE_ID>:自分のベクターストアID(例:vs_xxx...)<LOCAL_DIR>:分割したPDFを格納しているローカルフォルダの絶対パス<BASE_FILENAME_PATTERN>:分割ファイルの共通パターン。{0}が連番に置換されます(例:MyDoc_Part{0}.pdf)<FIRST_INDEX>/<LAST_INDEX>:連番の開始・終了(例:1〜9)OPENAI_API_KEYは各自の環境変数に設定しておく(キー自体はこのドキュメントに記載しない)
実行前チェック
- PowerShell 5.1 以上
curl.exeとInvoke-RestMethodが使えることecho $env:OPENAI_API_KEYでキーが見えること(キーは貼らない)
スクリプト(テンプレート)
powershell
# ========= 設定(各自で置き換え)=========
$vsId = "<VECTOR_STORE_ID>" # 例: vs_********************************
$apiKey = $env:OPENAI_API_KEY # 事前に環境変数に設定しておく
$dir = "<LOCAL_DIR>" # 例: C:\path\to\split_pdfs
$base = "<BASE_FILENAME_PATTERN>" # 例: MyDoc_Part{0}.pdf
$start = <FIRST_INDEX> # 例: 1
$end = <LAST_INDEX> # 例: 9
# ========= 共通ヘッダー =========
$headersJson = @{ "Authorization"="Bearer $apiKey"; "Content-Type"="application/json" }
$headersGet = @{ "Authorization"="Bearer $apiKey" }
# ========= HTTPエラー本文取得(見やすいログ用)=========
function Get-HttpErrorBody([System.Management.Automation.ErrorRecord]$err) {
try {
$resp = $err.Exception.Response
if ($resp -and $resp.GetResponseStream) {
$sr = New-Object System.IO.StreamReader($resp.GetResponseStream())
return $sr.ReadToEnd()
}
} catch { }
return $err.Exception.Message
}
# ========= 1ファイル処理 =========
function Invoke-UploadAndAttach {
param(
[Parameter(Mandatory=$true)][string]$FilePath,
[Parameter(Mandatory=$true)][string]$VectorStoreId
)
$partName = [System.IO.Path]::GetFileName($FilePath)
if (!(Test-Path -LiteralPath $FilePath)) {
return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="missing"; Error="File not found" }
}
Write-Host "`n=== Uploading: $partName ==="
# 1) アップロード(purpose=assistants)
$upload = curl.exe -s -X POST "https://api.openai.com/v1/files" `
-H "Authorization: Bearer $apiKey" `
-F "purpose=assistants" `
-F "file=@$FilePath"
try { $uobj = $upload | ConvertFrom-Json } catch {
return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="upload_failed"; Error="Invalid upload JSON: $upload" }
}
if ($uobj.error) {
$msg = if ($uobj.error.message) { $uobj.error.message } else { "Upload error" }
return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="upload_failed"; Error=$msg }
}
$fileId = $uobj.id
if (-not $fileId) {
return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="upload_failed"; Error="No file id in upload response" }
}
Write-Host "uploaded file_id: $fileId"
# 2) ベクターストアへアタッチ(指数バックオフ)
$payload = @{ file_id = $fileId } | ConvertTo-Json -Compress
$maxAttempts = 5
$attached = $false
for ($a=1; $a -le $maxAttempts; $a++) {
try {
$attach = Invoke-RestMethod -Method Post `
-Uri "https://api.openai.com/v1/vector_stores/$VectorStoreId/files" `
-Headers $headersJson -Body $payload
Write-Host "attached: $($attach.id) -> status: $($attach.status)"
$attached = $true
break
} catch {
$body = Get-HttpErrorBody $_
Write-Warning "[Attempt $a/$maxAttempts] attach failed: $body"
if ($a -lt $maxAttempts) { Start-Sleep -Seconds ([Math]::Min(10, [Math]::Pow(2, $a))) }
}
}
if (-not $attached) {
return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="attach_failed"; Error="Attach failed after retries" }
}
# 3) ステータス監視(最大 8 分)
$deadline = (Get-Date).AddMinutes(8)
do {
Start-Sleep -Seconds 3
try {
$status = Invoke-RestMethod -Method Get `
-Uri "https://api.openai.com/v1/vector_stores/$VectorStoreId/files/$fileId" `
-Headers $headersGet
Write-Host "status: $($status.status)"
if ($status.status -in @("completed","failed")) {
if ($status.status -eq "failed") {
$err = if ($status.last_error) { ($status.last_error | Out-String).Trim() } else { "Unknown ingestion error" }
return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="failed"; Error=$err }
} else {
return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="completed"; Error=$null }
}
}
} catch {
$body = Get-HttpErrorBody $_
Write-Warning "status check error: $body"
}
} while ((Get-Date) -lt $deadline)
return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="timeout"; Error="Ingestion did not finish in 8 minutes" }
}
# ========= メイン(連番ファイルを処理)=========
$results = @()
$start..$end | ForEach-Object {
$path = Join-Path -Path $dir -ChildPath ($base -f $_)
$results += Invoke-UploadAndAttach -FilePath $path -VectorStoreId $vsId
}
# ========= サマリー =========
"`n===== SUMMARY ====="
$results | Format-Table -AutoSize
$failed = $results | Where-Object { $_.Status -ne "completed" }
if ($failed) {
"`nSome items did not complete:"
$failed | ForEach-Object { " - $($_.Part): $($_.Status) $($_.Error)" }
} else {
"`n✅ All parts completed"
}Author: 村井 | Source:
村井\uPano×MetaQuest3でパノラマビューアプリデモ開発\OpenAI APIでRAGのやり方 287aba435ee780bab388d2ac0d2ea573.md