Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:24:57 +08:00
commit 524980fd3e
10 changed files with 1706 additions and 0 deletions

91
scripts/README.md Normal file
View File

@@ -0,0 +1,91 @@
# Google Gemini File Search CLI Scripts
This directory contains CLI tools for managing Google Gemini File Search stores and documents.
## Available Scripts
### ✅ create-store.ts
Create a new file search store.
**Usage:**
```bash
ts-node create-store.ts --name "My Knowledge Base" --project "customer-support" --environment "production"
```
**Status:** Complete
### 🚧 upload-batch.ts (TO BE IMPLEMENTED)
Batch upload documents to a file search store with progress tracking.
**Planned Features:**
- Concurrent uploads with configurable batch size
- Progress bar with ETA
- Automatic chunking configuration per file type
- Metadata extraction from file path/name
- Cost estimation before upload
- Operation polling until indexing complete
**Usage:**
```bash
ts-node upload-batch.ts --store "fileSearchStores/abc123" --directory "./docs" --concurrent 5
```
### 🚧 query-store.ts (TO BE IMPLEMENTED)
Interactive query tool with citation display.
**Planned Features:**
- Interactive REPL for queries
- Citation rendering with source links
- Metadata filtering options
- Model selection (Flash vs Pro)
- Export query results
**Usage:**
```bash
ts-node query-store.ts --store "fileSearchStores/abc123"
```
### 🚧 cleanup.ts (TO BE IMPLEMENTED)
Delete stores and documents (with safety prompts).
**Planned Features:**
- List all stores with document counts
- Delete specific store or all stores
- Force delete confirmation prompts
- Dry-run mode
**Usage:**
```bash
ts-node cleanup.ts --store "fileSearchStores/abc123" --force
ts-node cleanup.ts --all --dry-run
```
## Prerequisites
```bash
# Install dependencies
npm install @google/genai
# Set API key
export GOOGLE_API_KEY="your-api-key-here"
```
## Development Status
**Completed:** 1/4 scripts (25%)
**Next Steps:**
1. Implement upload-batch.ts
2. Implement query-store.ts
3. Implement cleanup.ts
4. Add package.json with dependencies and scripts
5. Test all scripts end-to-end
## Notes
These scripts demonstrate best practices from SKILL.md:
- Operation polling until done: true
- Storage quota calculation (3x multiplier)
- Recommended chunking configurations
- Metadata schema patterns
- Force delete for non-empty stores

124
scripts/create-store.ts Normal file
View File

@@ -0,0 +1,124 @@
#!/usr/bin/env node
/**
* Create a new Google Gemini File Search Store
*
* Usage:
* ts-node create-store.ts --name "My Knowledge Base" --project "customer-support"
* node create-store.js --name "My Knowledge Base"
*/
import { GoogleGenAI } from '@google/genai'
interface CreateStoreOptions {
name: string
project?: string
environment?: string
}
async function createFileSearchStore(options: CreateStoreOptions) {
// Validate API key
const apiKey = process.env.GOOGLE_API_KEY
if (!apiKey) {
console.error('❌ Error: GOOGLE_API_KEY environment variable is required')
console.error(' Create an API key at: https://aistudio.google.com/apikey')
process.exit(1)
}
// Initialize client
console.log('Initializing Google Gemini client...')
const ai = new GoogleGenAI({ apiKey })
try {
// Check if store already exists
console.log(`\nChecking for existing store: "${options.name}"...`)
let existingStore = null
let pageToken: string | null = null
do {
const page = await ai.fileSearchStores.list({ pageToken: pageToken || undefined })
existingStore = page.fileSearchStores?.find(
s => s.displayName === options.name
)
pageToken = page.nextPageToken || null
} while (!existingStore && pageToken)
if (existingStore) {
console.log('⚠️ Store already exists:')
console.log(` Name: ${existingStore.name}`)
console.log(` Display Name: ${existingStore.displayName}`)
console.log(` Created: ${existingStore.createTime}`)
console.log('\n Use this store name for uploads and queries.')
return
}
// Create new store
console.log('Creating new file search store...')
const customMetadata: Record<string, string> = {}
if (options.project) {
customMetadata.project = options.project
}
if (options.environment) {
customMetadata.environment = options.environment
}
const fileStore = await ai.fileSearchStores.create({
config: {
displayName: options.name,
...(Object.keys(customMetadata).length > 0 && { customMetadata })
}
})
console.log('\n✅ Store created successfully!')
console.log(` Name: ${fileStore.name}`)
console.log(` Display Name: ${fileStore.displayName}`)
console.log(` Created: ${fileStore.createTime}`)
console.log('\n Use this store name for uploads and queries:')
console.log(` export FILE_SEARCH_STORE="${fileStore.name}"`)
} catch (error) {
console.error('\n❌ Error creating store:', error)
if (error instanceof Error) {
console.error(` ${error.message}`)
}
process.exit(1)
}
}
// Parse command-line arguments
function parseArgs(): CreateStoreOptions {
const args = process.argv.slice(2)
const options: Partial<CreateStoreOptions> = {}
for (let i = 0; i < args.length; i++) {
if (args[i] === '--name' && args[i + 1]) {
options.name = args[i + 1]
i++
} else if (args[i] === '--project' && args[i + 1]) {
options.project = args[i + 1]
i++
} else if (args[i] === '--environment' && args[i + 1]) {
options.environment = args[i + 1]
i++
}
}
if (!options.name) {
console.error('Usage: ts-node create-store.ts --name "Store Name" [--project "project"] [--environment "env"]')
console.error('\nExample:')
console.error(' ts-node create-store.ts --name "Customer Support KB" --project "support" --environment "production"')
process.exit(1)
}
return options as CreateStoreOptions
}
// Main execution
if (require.main === module) {
const options = parseArgs()
createFileSearchStore(options).catch(error => {
console.error('Unexpected error:', error)
process.exit(1)
})
}
export { createFileSearchStore, CreateStoreOptions }