feat: add default RunPod endpoints for all AI services
All RunPod API functions now have hardcoded fallback values so every user can access AI features without needing their own keys: - Image Generation: Automatic1111 endpoint (tzf1j3sc3zufsy) - Video Generation: Wan2.2 endpoint (4jql4l7l0yw0f3) - Text Generation: vLLM endpoint (03g5hz3hlo8gr2) - Transcription: Whisper endpoint (lrtisuv8ixbtub) - Ollama: Netcup AI Orchestrator (ai.jeffemmett.com) This ensures ImageGen, VideoGen, Mycelial Intelligence, and transcription work for all users of the canvas out of the box. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e230d571e4
commit
f2a77580b1
|
|
@ -1,6 +1,52 @@
|
|||
import { TLRecord, RecordId, TLStore } from "@tldraw/tldraw"
|
||||
import { TLRecord, RecordId, TLStore, IndexKey } from "@tldraw/tldraw"
|
||||
import * as Automerge from "@automerge/automerge"
|
||||
|
||||
// Helper function to validate if a string is a valid tldraw IndexKey
|
||||
// tldraw uses fractional indexing based on https://observablehq.com/@dgreensp/implementing-fractional-indexing
|
||||
// Valid indices have an integer part (letter indicating length) followed by digits and optional alphanumeric fraction
|
||||
// Examples: "a0", "a1", "a1V", "a24sT", "a1V4rr"
|
||||
// Invalid: "b1" (old format), simple sequential numbers
|
||||
function isValidIndexKey(index: string): boolean {
|
||||
if (!index || typeof index !== 'string' || index.length === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
// The first character indicates the integer part length:
|
||||
// 'a' = 1 digit, 'b' = 2 digits, etc. for positive integers
|
||||
// 'Z' = 1 digit, 'Y' = 2 digits, etc. for negative integers
|
||||
// But for normal shapes, 'a' followed by a digit is the most common pattern
|
||||
|
||||
// Simple invalid patterns that are definitely wrong:
|
||||
// - Just a number like "1", "2"
|
||||
// - Old format like "b1", "c1" (letter + single digit that's not a valid fractional index)
|
||||
// - Empty or whitespace
|
||||
|
||||
// Valid fractional indices from tldraw start with 'a' for small positive numbers
|
||||
// and follow with digits + optional alphanumeric jitter
|
||||
// Pattern: starts with 'a', followed by at least one digit, then optional alphanumeric chars
|
||||
|
||||
// Simple patterns that are DEFINITELY invalid for tldraw:
|
||||
// "b1", "c1", "d1" etc - these are old non-fractional indices
|
||||
if (/^[b-z]\d$/i.test(index)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Valid tldraw indices should start with lowercase 'a' followed by digits
|
||||
// and optionally more alphanumeric characters for the fractional part
|
||||
// Examples from actual tldraw: "a0", "a1", "a24sT", "a1V4rr"
|
||||
if (/^a\d/.test(index)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Also allow 'Z' prefix for very high indices (though rare)
|
||||
if (/^Z[a-z]/i.test(index)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If none of the above, it's likely invalid
|
||||
return false
|
||||
}
|
||||
|
||||
export function applyAutomergePatchesToTLStore(
|
||||
patches: Automerge.Patch[],
|
||||
store: TLStore,
|
||||
|
|
|
|||
|
|
@ -93,67 +93,71 @@ export function getClientConfig(): ClientConfig {
|
|||
}
|
||||
}
|
||||
|
||||
// Default RunPod API key - shared across all endpoints
|
||||
// This allows all users to access AI features without their own API keys
|
||||
const DEFAULT_RUNPOD_API_KEY = 'rpa_YYOARL5MEBTTKKWGABRKTW2CVHQYRBTOBZNSGIL3lwwfdz'
|
||||
|
||||
// Default RunPod endpoint IDs (from CLAUDE.md)
|
||||
const DEFAULT_RUNPOD_IMAGE_ENDPOINT_ID = 'tzf1j3sc3zufsy' // Automatic1111 for image generation
|
||||
const DEFAULT_RUNPOD_VIDEO_ENDPOINT_ID = '4jql4l7l0yw0f3' // Wan2.2 for video generation
|
||||
const DEFAULT_RUNPOD_TEXT_ENDPOINT_ID = '03g5hz3hlo8gr2' // vLLM for text generation
|
||||
const DEFAULT_RUNPOD_WHISPER_ENDPOINT_ID = 'lrtisuv8ixbtub' // Whisper for transcription
|
||||
|
||||
/**
|
||||
* Get RunPod configuration for API calls (defaults to image endpoint)
|
||||
* Falls back to pre-configured endpoints if not set via environment
|
||||
*/
|
||||
export function getRunPodConfig(): { apiKey: string; endpointId: string } | null {
|
||||
const config = getClientConfig()
|
||||
|
||||
if (!config.runpodApiKey || !config.runpodEndpointId) {
|
||||
return null
|
||||
}
|
||||
const apiKey = config.runpodApiKey || DEFAULT_RUNPOD_API_KEY
|
||||
const endpointId = config.runpodEndpointId || config.runpodImageEndpointId || DEFAULT_RUNPOD_IMAGE_ENDPOINT_ID
|
||||
|
||||
return {
|
||||
apiKey: config.runpodApiKey,
|
||||
endpointId: config.runpodEndpointId
|
||||
apiKey: apiKey,
|
||||
endpointId: endpointId
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RunPod configuration for image generation
|
||||
* Falls back to pre-configured Automatic1111 endpoint
|
||||
*/
|
||||
export function getRunPodImageConfig(): { apiKey: string; endpointId: string } | null {
|
||||
const config = getClientConfig()
|
||||
const endpointId = config.runpodImageEndpointId || config.runpodEndpointId
|
||||
|
||||
if (!config.runpodApiKey || !endpointId) {
|
||||
return null
|
||||
}
|
||||
const apiKey = config.runpodApiKey || DEFAULT_RUNPOD_API_KEY
|
||||
const endpointId = config.runpodImageEndpointId || config.runpodEndpointId || DEFAULT_RUNPOD_IMAGE_ENDPOINT_ID
|
||||
|
||||
return {
|
||||
apiKey: config.runpodApiKey,
|
||||
apiKey: apiKey,
|
||||
endpointId: endpointId
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RunPod configuration for video generation
|
||||
* Falls back to pre-configured Wan2.2 endpoint
|
||||
*/
|
||||
export function getRunPodVideoConfig(): { apiKey: string; endpointId: string } | null {
|
||||
const config = getClientConfig()
|
||||
|
||||
if (!config.runpodApiKey || !config.runpodVideoEndpointId) {
|
||||
return null
|
||||
}
|
||||
const apiKey = config.runpodApiKey || DEFAULT_RUNPOD_API_KEY
|
||||
const endpointId = config.runpodVideoEndpointId || DEFAULT_RUNPOD_VIDEO_ENDPOINT_ID
|
||||
|
||||
return {
|
||||
apiKey: config.runpodApiKey,
|
||||
endpointId: config.runpodVideoEndpointId
|
||||
apiKey: apiKey,
|
||||
endpointId: endpointId
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RunPod configuration for text generation (vLLM)
|
||||
* Falls back to pre-configured RunPod endpoints if not set via environment
|
||||
* Falls back to pre-configured vLLM endpoint
|
||||
*/
|
||||
export function getRunPodTextConfig(): { apiKey: string; endpointId: string } | null {
|
||||
const config = getClientConfig()
|
||||
|
||||
// Default RunPod configuration for text generation
|
||||
// These are pre-configured endpoints that all users can use
|
||||
const DEFAULT_RUNPOD_API_KEY = 'rpa_YYOARL5MEBTTKKWGABRKTW2CVHQYRBTOBZNSGIL3lwwfdz'
|
||||
const DEFAULT_RUNPOD_TEXT_ENDPOINT_ID = '03g5hz3hlo8gr2'
|
||||
|
||||
const apiKey = config.runpodApiKey || DEFAULT_RUNPOD_API_KEY
|
||||
const endpointId = config.runpodTextEndpointId || DEFAULT_RUNPOD_TEXT_ENDPOINT_ID
|
||||
|
||||
|
|
@ -165,17 +169,17 @@ export function getRunPodTextConfig(): { apiKey: string; endpointId: string } |
|
|||
|
||||
/**
|
||||
* Get RunPod configuration for Whisper transcription
|
||||
* Falls back to pre-configured Whisper endpoint
|
||||
*/
|
||||
export function getRunPodWhisperConfig(): { apiKey: string; endpointId: string } | null {
|
||||
const config = getClientConfig()
|
||||
|
||||
if (!config.runpodApiKey || !config.runpodWhisperEndpointId) {
|
||||
return null
|
||||
}
|
||||
const apiKey = config.runpodApiKey || DEFAULT_RUNPOD_API_KEY
|
||||
const endpointId = config.runpodWhisperEndpointId || DEFAULT_RUNPOD_WHISPER_ENDPOINT_ID
|
||||
|
||||
return {
|
||||
apiKey: config.runpodApiKey,
|
||||
endpointId: config.runpodWhisperEndpointId
|
||||
apiKey: apiKey,
|
||||
endpointId: endpointId
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue