@geenius/ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/config.json +11 -0
- package/.env.example +2 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +11 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +10 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/ci.yml +23 -0
- package/.github/workflows/release.yml +29 -0
- package/.node-version +1 -0
- package/.nvmrc +1 -0
- package/.prettierrc +7 -0
- package/.project/ACCOUNT.yaml +4 -0
- package/.project/IDEAS.yaml +7 -0
- package/.project/PROJECT.yaml +11 -0
- package/.project/ROADMAP.yaml +15 -0
- package/CHANGELOG.md +15 -0
- package/CODE_OF_CONDUCT.md +26 -0
- package/CONTRIBUTING.md +61 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/SECURITY.md +18 -0
- package/SUPPORT.md +14 -0
- package/package.json +75 -0
- package/packages/convex/package.json +42 -0
- package/packages/convex/src/index.ts +8 -0
- package/packages/convex/src/mutations/messages.ts +29 -0
- package/packages/convex/src/queries/messages.ts +24 -0
- package/packages/convex/src/schema.ts +20 -0
- package/packages/convex/tsconfig.json +11 -0
- package/packages/convex/tsup.config.ts +17 -0
- package/packages/react/README.md +1 -0
- package/packages/react/package.json +60 -0
- package/packages/react/src/components/AILogTable.tsx +90 -0
- package/packages/react/src/components/ChatWindow.tsx +118 -0
- package/packages/react/src/components/GenerationCard.tsx +73 -0
- package/packages/react/src/components/ImageGenerator.tsx +103 -0
- package/packages/react/src/components/ModelSelector.tsx +44 -0
- package/packages/react/src/components/ModelTestRunner.tsx +148 -0
- package/packages/react/src/components/VoiceSelector.tsx +51 -0
- package/packages/react/src/components/index.ts +9 -0
- package/packages/react/src/hooks/index.ts +12 -0
- package/packages/react/src/hooks/useAI.ts +158 -0
- package/packages/react/src/hooks/useAILogs.ts +40 -0
- package/packages/react/src/hooks/useAIModels.ts +53 -0
- package/packages/react/src/hooks/useChat.ts +141 -0
- package/packages/react/src/hooks/useContentManager.ts +108 -0
- package/packages/react/src/hooks/useImageGeneration.ts +82 -0
- package/packages/react/src/hooks/useMemory.ts +161 -0
- package/packages/react/src/hooks/useModelTest.ts +126 -0
- package/packages/react/src/hooks/useRealtimeAudio.ts +203 -0
- package/packages/react/src/hooks/useSkills.ts +114 -0
- package/packages/react/src/hooks/useTextToSpeech.ts +99 -0
- package/packages/react/src/hooks/useTranscription.ts +119 -0
- package/packages/react/src/hooks/useVideoGeneration.ts +79 -0
- package/packages/react/src/index.ts +42 -0
- package/packages/react/src/pages/AILogsPage.tsx +98 -0
- package/packages/react/src/pages/ChatPage.tsx +42 -0
- package/packages/react/src/pages/ModelTestPage.tsx +33 -0
- package/packages/react/src/pages/index.ts +5 -0
- package/packages/react/tsconfig.json +26 -0
- package/packages/react/tsup.config.ts +22 -0
- package/packages/react-css/README.md +1 -0
- package/packages/react-css/package.json +45 -0
- package/packages/react-css/src/ai.css +857 -0
- package/packages/react-css/src/components/AILogTable.tsx +90 -0
- package/packages/react-css/src/components/ChatWindow.tsx +118 -0
- package/packages/react-css/src/components/GenerationCard.tsx +73 -0
- package/packages/react-css/src/components/ImageGenerator.tsx +103 -0
- package/packages/react-css/src/components/ModelSelector.tsx +44 -0
- package/packages/react-css/src/components/ModelTestRunner.tsx +148 -0
- package/packages/react-css/src/components/VoiceSelector.tsx +51 -0
- package/packages/react-css/src/components/index.ts +9 -0
- package/packages/react-css/src/hooks/index.ts +12 -0
- package/packages/react-css/src/hooks/useAI.ts +153 -0
- package/packages/react-css/src/hooks/useAILogs.ts +40 -0
- package/packages/react-css/src/hooks/useAIModels.ts +51 -0
- package/packages/react-css/src/hooks/useChat.ts +145 -0
- package/packages/react-css/src/hooks/useContentManager.ts +108 -0
- package/packages/react-css/src/hooks/useImageGeneration.ts +82 -0
- package/packages/react-css/src/hooks/useMemory.ts +161 -0
- package/packages/react-css/src/hooks/useModelTest.ts +122 -0
- package/packages/react-css/src/hooks/useRealtimeAudio.ts +203 -0
- package/packages/react-css/src/hooks/useSkills.ts +114 -0
- package/packages/react-css/src/hooks/useTextToSpeech.ts +99 -0
- package/packages/react-css/src/hooks/useTranscription.ts +119 -0
- package/packages/react-css/src/hooks/useVideoGeneration.ts +79 -0
- package/packages/react-css/src/index.ts +35 -0
- package/packages/react-css/src/pages/AILogsPage.tsx +98 -0
- package/packages/react-css/src/pages/ChatPage.tsx +42 -0
- package/packages/react-css/src/pages/ModelTestPage.tsx +33 -0
- package/packages/react-css/src/pages/index.ts +5 -0
- package/packages/react-css/src/styles.css +127 -0
- package/packages/react-css/tsconfig.json +26 -0
- package/packages/react-css/tsup.config.ts +2 -0
- package/packages/shared/README.md +1 -0
- package/packages/shared/package.json +71 -0
- package/packages/shared/src/__tests__/ai.test.ts +67 -0
- package/packages/shared/src/ai-client.ts +243 -0
- package/packages/shared/src/config.ts +235 -0
- package/packages/shared/src/content.ts +249 -0
- package/packages/shared/src/convex/helpers.ts +163 -0
- package/packages/shared/src/convex/index.ts +16 -0
- package/packages/shared/src/convex/schemas.ts +146 -0
- package/packages/shared/src/convex/validators.ts +136 -0
- package/packages/shared/src/index.ts +107 -0
- package/packages/shared/src/memory.ts +197 -0
- package/packages/shared/src/providers/base.ts +103 -0
- package/packages/shared/src/providers/elevenlabs.ts +155 -0
- package/packages/shared/src/providers/index.ts +28 -0
- package/packages/shared/src/providers/openai-compatible.ts +286 -0
- package/packages/shared/src/providers/registry.ts +113 -0
- package/packages/shared/src/providers/replicate-fal.ts +230 -0
- package/packages/shared/src/skills.ts +273 -0
- package/packages/shared/src/types.ts +501 -0
- package/packages/shared/tsconfig.json +25 -0
- package/packages/shared/tsup.config.ts +22 -0
- package/packages/shared/vitest.config.ts +4 -0
- package/packages/solidjs/README.md +1 -0
- package/packages/solidjs/package.json +59 -0
- package/packages/solidjs/src/components/ChatWindow.tsx +78 -0
- package/packages/solidjs/src/components/GenerationCard.tsx +62 -0
- package/packages/solidjs/src/components/ModelTestRunner.tsx +119 -0
- package/packages/solidjs/src/components/index.ts +5 -0
- package/packages/solidjs/src/index.ts +32 -0
- package/packages/solidjs/src/pages/ChatPage.tsx +22 -0
- package/packages/solidjs/src/pages/ModelTestPage.tsx +22 -0
- package/packages/solidjs/src/pages/index.ts +4 -0
- package/packages/solidjs/src/primitives/createAI.ts +79 -0
- package/packages/solidjs/src/primitives/createChat.ts +100 -0
- package/packages/solidjs/src/primitives/createContentManager.ts +61 -0
- package/packages/solidjs/src/primitives/createImageGeneration.ts +46 -0
- package/packages/solidjs/src/primitives/createMemory.ts +127 -0
- package/packages/solidjs/src/primitives/createModelTest.ts +89 -0
- package/packages/solidjs/src/primitives/createSkills.ts +83 -0
- package/packages/solidjs/src/primitives/createTextToSpeech.ts +56 -0
- package/packages/solidjs/src/primitives/createVideoGeneration.ts +46 -0
- package/packages/solidjs/src/primitives/index.ts +8 -0
- package/packages/solidjs/tsconfig.json +27 -0
- package/packages/solidjs/tsup.config.ts +21 -0
- package/packages/solidjs-css/README.md +1 -0
- package/packages/solidjs-css/package.json +44 -0
- package/packages/solidjs-css/src/ai.css +857 -0
- package/packages/solidjs-css/src/components/ChatWindow.tsx +78 -0
- package/packages/solidjs-css/src/components/GenerationCard.tsx +62 -0
- package/packages/solidjs-css/src/components/ModelTestRunner.tsx +119 -0
- package/packages/solidjs-css/src/components/index.ts +5 -0
- package/packages/solidjs-css/src/index.ts +26 -0
- package/packages/solidjs-css/src/pages/ChatPage.tsx +22 -0
- package/packages/solidjs-css/src/pages/ModelTestPage.tsx +22 -0
- package/packages/solidjs-css/src/pages/index.ts +4 -0
- package/packages/solidjs-css/src/primitives/createAI.ts +79 -0
- package/packages/solidjs-css/src/primitives/createChat.ts +100 -0
- package/packages/solidjs-css/src/primitives/createContentManager.ts +61 -0
- package/packages/solidjs-css/src/primitives/createImageGeneration.ts +46 -0
- package/packages/solidjs-css/src/primitives/createMemory.ts +127 -0
- package/packages/solidjs-css/src/primitives/createModelTest.ts +89 -0
- package/packages/solidjs-css/src/primitives/createSkills.ts +83 -0
- package/packages/solidjs-css/src/primitives/createTextToSpeech.ts +56 -0
- package/packages/solidjs-css/src/primitives/createVideoGeneration.ts +46 -0
- package/packages/solidjs-css/src/primitives/index.ts +1 -0
- package/packages/solidjs-css/src/styles.css +127 -0
- package/packages/solidjs-css/tsconfig.json +27 -0
- package/packages/solidjs-css/tsup.config.ts +2 -0
- package/pnpm-workspace.yaml +2 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// @geenius-ai/shared — src/convex/validators.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convex validators for AI actions, queries, and mutations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { v } from 'convex/values'
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Action Validators
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
export const generateTextArgs = {
|
|
14
|
+
model: v.string(),
|
|
15
|
+
messages: v.any(), // AIMessage[]
|
|
16
|
+
temperature: v.optional(v.number()),
|
|
17
|
+
maxTokens: v.optional(v.number()),
|
|
18
|
+
topP: v.optional(v.number()),
|
|
19
|
+
caller: v.optional(v.string()),
|
|
20
|
+
responseFormat: v.optional(v.any()),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const generateImageArgs = {
|
|
24
|
+
model: v.optional(v.string()),
|
|
25
|
+
prompt: v.string(),
|
|
26
|
+
n: v.optional(v.number()),
|
|
27
|
+
size: v.optional(v.string()),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const generateAudioArgs = {
|
|
31
|
+
model: v.optional(v.string()),
|
|
32
|
+
prompt: v.string(),
|
|
33
|
+
voice: v.optional(v.string()),
|
|
34
|
+
speed: v.optional(v.number()),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const transcribeAudioArgs = {
|
|
38
|
+
model: v.optional(v.string()),
|
|
39
|
+
audio: v.string(),
|
|
40
|
+
language: v.optional(v.string()),
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const generateVideoArgs = {
|
|
44
|
+
model: v.optional(v.string()),
|
|
45
|
+
prompt: v.string(),
|
|
46
|
+
duration: v.optional(v.number()),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const testModelArgs = {
|
|
50
|
+
model: v.string(),
|
|
51
|
+
prompt: v.string(),
|
|
52
|
+
temperature: v.optional(v.number()),
|
|
53
|
+
maxTokens: v.optional(v.number()),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Log Validators
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
export const saveLogArgs = {
|
|
61
|
+
requestId: v.string(),
|
|
62
|
+
model: v.string(),
|
|
63
|
+
provider: v.string(),
|
|
64
|
+
caller: v.string(),
|
|
65
|
+
type: v.string(),
|
|
66
|
+
timestamp: v.number(),
|
|
67
|
+
durationMs: v.number(),
|
|
68
|
+
systemPrompt: v.string(),
|
|
69
|
+
userPrompt: v.string(),
|
|
70
|
+
hasImage: v.boolean(),
|
|
71
|
+
imageSizeBytes: v.optional(v.number()),
|
|
72
|
+
temperature: v.optional(v.number()),
|
|
73
|
+
maxTokens: v.optional(v.number()),
|
|
74
|
+
requestBodySize: v.number(),
|
|
75
|
+
status: v.union(v.literal('success'), v.literal('error')),
|
|
76
|
+
httpStatus: v.number(),
|
|
77
|
+
responseContent: v.string(),
|
|
78
|
+
responseSize: v.number(),
|
|
79
|
+
finishReason: v.optional(v.string()),
|
|
80
|
+
promptTokens: v.optional(v.number()),
|
|
81
|
+
completionTokens: v.optional(v.number()),
|
|
82
|
+
totalTokens: v.optional(v.number()),
|
|
83
|
+
errorMessage: v.optional(v.string()),
|
|
84
|
+
inputCostUsd: v.optional(v.number()),
|
|
85
|
+
outputCostUsd: v.optional(v.number()),
|
|
86
|
+
totalCostUsd: v.optional(v.number()),
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const listLogsArgs = {
|
|
90
|
+
model: v.optional(v.string()),
|
|
91
|
+
provider: v.optional(v.string()),
|
|
92
|
+
status: v.optional(v.union(v.literal('success'), v.literal('error'))),
|
|
93
|
+
caller: v.optional(v.string()),
|
|
94
|
+
limit: v.optional(v.number()),
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// Model Cost Validators
|
|
99
|
+
// ============================================================================
|
|
100
|
+
|
|
101
|
+
export const upsertModelArgs = {
|
|
102
|
+
model: v.string(),
|
|
103
|
+
provider: v.string(),
|
|
104
|
+
displayName: v.optional(v.string()),
|
|
105
|
+
inputCostPer1k: v.number(),
|
|
106
|
+
outputCostPer1k: v.number(),
|
|
107
|
+
capabilities: v.optional(v.array(v.string())),
|
|
108
|
+
contextWindow: v.optional(v.number()),
|
|
109
|
+
isActive: v.optional(v.boolean()),
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Conversation Validators
|
|
114
|
+
// ============================================================================
|
|
115
|
+
|
|
116
|
+
export const createConversationArgs = {
|
|
117
|
+
title: v.string(),
|
|
118
|
+
model: v.string(),
|
|
119
|
+
systemPrompt: v.optional(v.string()),
|
|
120
|
+
tags: v.optional(v.array(v.string())),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const updateConversationArgs = {
|
|
124
|
+
conversationId: v.id('aiConversations'),
|
|
125
|
+
title: v.optional(v.string()),
|
|
126
|
+
model: v.optional(v.string()),
|
|
127
|
+
systemPrompt: v.optional(v.string()),
|
|
128
|
+
tags: v.optional(v.array(v.string())),
|
|
129
|
+
favorite: v.optional(v.boolean()),
|
|
130
|
+
status: v.optional(v.union(v.literal('active'), v.literal('archived'))),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const sendMessageArgs = {
|
|
134
|
+
conversationId: v.id('aiConversations'),
|
|
135
|
+
content: v.string(),
|
|
136
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// @geenius-ai/shared — src/index.ts
|
|
2
|
+
|
|
3
|
+
// Types
|
|
4
|
+
export type {
|
|
5
|
+
AIProviderType,
|
|
6
|
+
AIGenerationType,
|
|
7
|
+
AIModelCapability,
|
|
8
|
+
AIModel,
|
|
9
|
+
AIProviderConfig,
|
|
10
|
+
AIMessageRole,
|
|
11
|
+
AIMessageContentPart,
|
|
12
|
+
AIMessage,
|
|
13
|
+
AIToolCall,
|
|
14
|
+
AIToolDefinition,
|
|
15
|
+
AIConversation,
|
|
16
|
+
AIConversationStatus,
|
|
17
|
+
AIChatMessage,
|
|
18
|
+
AIAttachment,
|
|
19
|
+
AIGenerateTextOptions,
|
|
20
|
+
AIStructuredOutputOptions,
|
|
21
|
+
AIGenerateImageOptions,
|
|
22
|
+
AIEditImageOptions,
|
|
23
|
+
AIGenerateAudioOptions,
|
|
24
|
+
AITranscribeOptions,
|
|
25
|
+
AIGenerateVideoOptions,
|
|
26
|
+
AIEmbeddingOptions,
|
|
27
|
+
AIGenerateMusicOptions,
|
|
28
|
+
AIGenerateSoundEffectOptions,
|
|
29
|
+
AIVoiceCloneOptions,
|
|
30
|
+
AIGenerationResult,
|
|
31
|
+
AIEmbeddingResult,
|
|
32
|
+
AITranscriptionResult,
|
|
33
|
+
AITranscriptionSegment,
|
|
34
|
+
AITranscriptionWord,
|
|
35
|
+
AIRealtimeConfig,
|
|
36
|
+
AIRealtimeEvent,
|
|
37
|
+
AILogEntry,
|
|
38
|
+
AIRequestStatus,
|
|
39
|
+
AIUsageStats,
|
|
40
|
+
AIConfig,
|
|
41
|
+
ChatWindowProps,
|
|
42
|
+
ModelTestPageProps,
|
|
43
|
+
AILogTableProps,
|
|
44
|
+
ImageGeneratorProps,
|
|
45
|
+
AudioPlayerProps,
|
|
46
|
+
VoiceSelectorProps,
|
|
47
|
+
AIVoiceOption,
|
|
48
|
+
RealtimeAudioProps,
|
|
49
|
+
} from './types'
|
|
50
|
+
|
|
51
|
+
// Config
|
|
52
|
+
export {
|
|
53
|
+
defineAIConfig,
|
|
54
|
+
mergeAIConfig,
|
|
55
|
+
findProviderConfig,
|
|
56
|
+
findModelConfig,
|
|
57
|
+
getProviderForModel,
|
|
58
|
+
getModelsByCapability,
|
|
59
|
+
DEFAULT_PROVIDERS,
|
|
60
|
+
DEFAULT_MODELS,
|
|
61
|
+
DEFAULT_VOICES,
|
|
62
|
+
} from './config'
|
|
63
|
+
|
|
64
|
+
// Content
|
|
65
|
+
export type {
|
|
66
|
+
ContentType,
|
|
67
|
+
ContentAction,
|
|
68
|
+
ContentTone,
|
|
69
|
+
ContentTemplate,
|
|
70
|
+
ContentOutputField,
|
|
71
|
+
ContentItem,
|
|
72
|
+
ContentSchema,
|
|
73
|
+
ContentFieldMeta,
|
|
74
|
+
ContentGenerateOptions,
|
|
75
|
+
ContentResult,
|
|
76
|
+
} from './content'
|
|
77
|
+
export { BUILT_IN_TEMPLATES, buildContentPrompt, buildActionSystemPrompt } from './content'
|
|
78
|
+
|
|
79
|
+
// Memory
|
|
80
|
+
export type {
|
|
81
|
+
MemoryNamespace,
|
|
82
|
+
MemoryType,
|
|
83
|
+
MemoryImportance,
|
|
84
|
+
MemoryEntry,
|
|
85
|
+
MemoryQuery,
|
|
86
|
+
MemoryStore,
|
|
87
|
+
UserPreference,
|
|
88
|
+
OrgPattern,
|
|
89
|
+
MemoryConfig,
|
|
90
|
+
} from './memory'
|
|
91
|
+
export { DEFAULT_MEMORY_CONFIG, buildMemoryContext, extractPreferenceHints } from './memory'
|
|
92
|
+
|
|
93
|
+
// Skills
|
|
94
|
+
export type {
|
|
95
|
+
SkillCategory,
|
|
96
|
+
SkillParameterType,
|
|
97
|
+
SkillParameter,
|
|
98
|
+
SkillDefinition,
|
|
99
|
+
SkillContext,
|
|
100
|
+
SkillResult,
|
|
101
|
+
SkillRegistry,
|
|
102
|
+
} from './skills'
|
|
103
|
+
export { BUILT_IN_SKILLS, createSkillRegistry, buildSkillPrompt } from './skills'
|
|
104
|
+
|
|
105
|
+
// Lightweight AI Client (fetch-based, no provider registry required)
|
|
106
|
+
export type { AIProvider, AIClientConfig, AIClientMessage, ToolCall, ToolDefinition, StreamCallbacks, AIResponse } from './ai-client'
|
|
107
|
+
export { resolveAIProvider, AIClient, createAI } from './ai-client'
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// @geenius-ai/shared — src/memory.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AI memory system — persistent, contextual memory for AI interactions.
|
|
5
|
+
* Supports user-level preferences, org-level patterns, and conversation memory.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AIProviderType } from './types'
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Memory Types
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
export type MemoryNamespace = 'user' | 'org' | 'conversation' | 'global'
|
|
15
|
+
export type MemoryType = 'preference' | 'pattern' | 'fact' | 'interaction' | 'feedback' | 'context'
|
|
16
|
+
export type MemoryImportance = 'low' | 'medium' | 'high' | 'critical'
|
|
17
|
+
|
|
18
|
+
export interface MemoryEntry {
|
|
19
|
+
id: string
|
|
20
|
+
namespace: MemoryNamespace
|
|
21
|
+
type: MemoryType
|
|
22
|
+
importance: MemoryImportance
|
|
23
|
+
/** The key identifying this memory (e.g., "preferred_tone", "date_format") */
|
|
24
|
+
key: string
|
|
25
|
+
/** The stored value */
|
|
26
|
+
value: string
|
|
27
|
+
/** Structured metadata */
|
|
28
|
+
metadata?: Record<string, unknown>
|
|
29
|
+
/** Embedding vector for semantic search */
|
|
30
|
+
embedding?: number[]
|
|
31
|
+
/** Namespace-scoped ID (userId, orgId, conversationId) */
|
|
32
|
+
scopeId: string
|
|
33
|
+
/** How many times this memory has been accessed */
|
|
34
|
+
accessCount: number
|
|
35
|
+
/** Last time this memory was accessed */
|
|
36
|
+
lastAccessedAt: number
|
|
37
|
+
/** When this memory expires (0 = never) */
|
|
38
|
+
expiresAt?: number
|
|
39
|
+
createdAt: number
|
|
40
|
+
updatedAt: number
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface MemoryQuery {
|
|
44
|
+
namespace?: MemoryNamespace
|
|
45
|
+
type?: MemoryType
|
|
46
|
+
key?: string
|
|
47
|
+
scopeId?: string
|
|
48
|
+
/** Semantic search query */
|
|
49
|
+
query?: string
|
|
50
|
+
/** Min importance level */
|
|
51
|
+
minImportance?: MemoryImportance
|
|
52
|
+
/** Max results */
|
|
53
|
+
limit?: number
|
|
54
|
+
/** Include expired entries */
|
|
55
|
+
includeExpired?: boolean
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface MemoryStore {
|
|
59
|
+
/** Store a new memory entry */
|
|
60
|
+
set(entry: Omit<MemoryEntry, 'id' | 'accessCount' | 'lastAccessedAt' | 'createdAt' | 'updatedAt'>): Promise<MemoryEntry>
|
|
61
|
+
/** Get a specific memory by key and scope */
|
|
62
|
+
get(namespace: MemoryNamespace, key: string, scopeId: string): Promise<MemoryEntry | null>
|
|
63
|
+
/** Search memories */
|
|
64
|
+
search(query: MemoryQuery): Promise<MemoryEntry[]>
|
|
65
|
+
/** Delete a memory */
|
|
66
|
+
delete(id: string): Promise<void>
|
|
67
|
+
/** Clear all memories in a namespace/scope */
|
|
68
|
+
clear(namespace: MemoryNamespace, scopeId: string): Promise<void>
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// User Preferences & Org Patterns
|
|
73
|
+
// ============================================================================
|
|
74
|
+
|
|
75
|
+
export interface UserPreference {
|
|
76
|
+
key: string
|
|
77
|
+
value: string
|
|
78
|
+
/** How confident we are in this preference (0-1) */
|
|
79
|
+
confidence: number
|
|
80
|
+
/** Number of times observed */
|
|
81
|
+
occurrences: number
|
|
82
|
+
/** Source of the preference */
|
|
83
|
+
source: 'explicit' | 'inferred' | 'default'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface OrgPattern {
|
|
87
|
+
key: string
|
|
88
|
+
value: string
|
|
89
|
+
/** How many users in the org follow this pattern */
|
|
90
|
+
adoptionRate: number
|
|
91
|
+
/** Description of the pattern */
|
|
92
|
+
description?: string
|
|
93
|
+
examples?: string[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// Memory Config
|
|
98
|
+
// ============================================================================
|
|
99
|
+
|
|
100
|
+
export interface MemoryConfig {
|
|
101
|
+
/** Enable memory system */
|
|
102
|
+
enabled: boolean
|
|
103
|
+
/** Max memories per namespace */
|
|
104
|
+
maxPerNamespace: number
|
|
105
|
+
/** Auto-expire memories after N days (0 = never) */
|
|
106
|
+
autoExpireDays: number
|
|
107
|
+
/** Enable semantic search (requires embedding model) */
|
|
108
|
+
semanticSearch: boolean
|
|
109
|
+
/** Embedding model to use */
|
|
110
|
+
embeddingModel?: string
|
|
111
|
+
/** Namespaces to enable */
|
|
112
|
+
enabledNamespaces: MemoryNamespace[]
|
|
113
|
+
/** Auto-extract preferences from conversations */
|
|
114
|
+
autoExtract: boolean
|
|
115
|
+
/** Max context tokens to inject from memory */
|
|
116
|
+
maxContextTokens: number
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const DEFAULT_MEMORY_CONFIG: MemoryConfig = {
|
|
120
|
+
enabled: true,
|
|
121
|
+
maxPerNamespace: 1000,
|
|
122
|
+
autoExpireDays: 0,
|
|
123
|
+
semanticSearch: false,
|
|
124
|
+
embeddingModel: 'text-embedding-3-small',
|
|
125
|
+
enabledNamespaces: ['user', 'org', 'conversation'],
|
|
126
|
+
autoExtract: true,
|
|
127
|
+
maxContextTokens: 2000,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ============================================================================
|
|
131
|
+
// Helpers
|
|
132
|
+
// ============================================================================
|
|
133
|
+
|
|
134
|
+
const IMPORTANCE_ORDER: Record<MemoryImportance, number> = {
|
|
135
|
+
low: 0,
|
|
136
|
+
medium: 1,
|
|
137
|
+
high: 2,
|
|
138
|
+
critical: 3,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Build a context string from relevant memories to inject into AI prompts.
|
|
143
|
+
*/
|
|
144
|
+
export function buildMemoryContext(
|
|
145
|
+
memories: MemoryEntry[],
|
|
146
|
+
maxTokens: number = 2000,
|
|
147
|
+
): string {
|
|
148
|
+
if (memories.length === 0) return ''
|
|
149
|
+
|
|
150
|
+
// Sort by importance (desc), then recency (desc)
|
|
151
|
+
const sorted = [...memories].sort((a, b) => {
|
|
152
|
+
const impDiff = IMPORTANCE_ORDER[b.importance] - IMPORTANCE_ORDER[a.importance]
|
|
153
|
+
if (impDiff !== 0) return impDiff
|
|
154
|
+
return b.lastAccessedAt - a.lastAccessedAt
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
const lines: string[] = ['<context_memory>']
|
|
158
|
+
let approxTokens = 4 // opening tag
|
|
159
|
+
|
|
160
|
+
for (const mem of sorted) {
|
|
161
|
+
const line = `- [${mem.type}] ${mem.key}: ${mem.value}`
|
|
162
|
+
const lineTokens = Math.ceil(line.length / 4) // rough token estimate
|
|
163
|
+
if (approxTokens + lineTokens > maxTokens) break
|
|
164
|
+
lines.push(line)
|
|
165
|
+
approxTokens += lineTokens
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
lines.push('</context_memory>')
|
|
169
|
+
return lines.join('\n')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Extract potential preferences from a conversation message.
|
|
174
|
+
*/
|
|
175
|
+
export function extractPreferenceHints(text: string): Array<{ key: string; value: string }> {
|
|
176
|
+
const hints: Array<{ key: string; value: string }> = []
|
|
177
|
+
|
|
178
|
+
// Language preferences
|
|
179
|
+
const langMatch = text.match(/(?:in|to|use)\s+(english|french|german|spanish|dutch|italian|portuguese|japanese|chinese|korean|arabic)/i)
|
|
180
|
+
if (langMatch) {
|
|
181
|
+
hints.push({ key: 'preferred_language', value: langMatch[1].toLowerCase() })
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Tone preferences
|
|
185
|
+
const toneMatch = text.match(/(?:tone|style|voice).*?(?:be|is|use)\s+(professional|casual|friendly|formal|technical)/i)
|
|
186
|
+
if (toneMatch) {
|
|
187
|
+
hints.push({ key: 'preferred_tone', value: toneMatch[1].toLowerCase() })
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Currency preferences
|
|
191
|
+
const currencyMatch = text.match(/(?:in|use)\s+(EUR|USD|GBP|JPY|CHF|CAD|AUD)(?:\b)/i)
|
|
192
|
+
if (currencyMatch) {
|
|
193
|
+
hints.push({ key: 'preferred_currency', value: currencyMatch[1].toUpperCase() })
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return hints
|
|
197
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// @geenius-ai/shared — src/providers/base.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base provider interface — all AI providers implement this.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
AIProviderType,
|
|
9
|
+
AIGenerationResult,
|
|
10
|
+
AIEmbeddingResult,
|
|
11
|
+
AITranscriptionResult,
|
|
12
|
+
AIGenerateTextOptions,
|
|
13
|
+
AIStructuredOutputOptions,
|
|
14
|
+
AIGenerateImageOptions,
|
|
15
|
+
AIEditImageOptions,
|
|
16
|
+
AIGenerateAudioOptions,
|
|
17
|
+
AITranscribeOptions,
|
|
18
|
+
AIGenerateVideoOptions,
|
|
19
|
+
AIEmbeddingOptions,
|
|
20
|
+
AIGenerateMusicOptions,
|
|
21
|
+
AIGenerateSoundEffectOptions,
|
|
22
|
+
AIVoiceCloneOptions,
|
|
23
|
+
AIMessage,
|
|
24
|
+
} from '../types'
|
|
25
|
+
|
|
26
|
+
export interface AIProviderInterface {
|
|
27
|
+
type: AIProviderType
|
|
28
|
+
name: string
|
|
29
|
+
|
|
30
|
+
/** Generate text completion. */
|
|
31
|
+
generateText(options: AIGenerateTextOptions): Promise<AIGenerationResult>
|
|
32
|
+
|
|
33
|
+
/** Generate structured JSON output. */
|
|
34
|
+
generateStructuredOutput?(options: AIStructuredOutputOptions): Promise<AIGenerationResult>
|
|
35
|
+
|
|
36
|
+
/** Generate an image from a text prompt. */
|
|
37
|
+
generateImage?(options: AIGenerateImageOptions): Promise<string>
|
|
38
|
+
|
|
39
|
+
/** Edit an existing image. */
|
|
40
|
+
editImage?(options: AIEditImageOptions): Promise<string>
|
|
41
|
+
|
|
42
|
+
/** Generate speech/audio from text (TTS). Returns base64. */
|
|
43
|
+
generateAudio?(options: AIGenerateAudioOptions): Promise<string>
|
|
44
|
+
|
|
45
|
+
/** Transcribe audio to text (ASR). */
|
|
46
|
+
transcribeAudio?(options: AITranscribeOptions): Promise<string | AITranscriptionResult>
|
|
47
|
+
|
|
48
|
+
/** Generate video from text prompt. Returns URL. */
|
|
49
|
+
generateVideo?(options: AIGenerateVideoOptions): Promise<string>
|
|
50
|
+
|
|
51
|
+
/** Generate embeddings. */
|
|
52
|
+
generateEmbeddings?(options: AIEmbeddingOptions): Promise<AIEmbeddingResult>
|
|
53
|
+
|
|
54
|
+
/** Generate music from text. Returns base64. */
|
|
55
|
+
generateMusic?(options: AIGenerateMusicOptions): Promise<string>
|
|
56
|
+
|
|
57
|
+
/** Generate sound effects. Returns base64. */
|
|
58
|
+
generateSoundEffect?(options: AIGenerateSoundEffectOptions): Promise<string>
|
|
59
|
+
|
|
60
|
+
/** Clone a voice from samples. Returns voice ID. */
|
|
61
|
+
cloneVoice?(options: AIVoiceCloneOptions): Promise<string>
|
|
62
|
+
|
|
63
|
+
/** List available voices. */
|
|
64
|
+
listVoices?(): Promise<Array<{ id: string; name: string; preview?: string }>>
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Extract text content from AIMessage array for logging.
|
|
69
|
+
*/
|
|
70
|
+
export function extractPromptText(messages: AIMessage[]): {
|
|
71
|
+
systemPrompt: string
|
|
72
|
+
userPromptText: string
|
|
73
|
+
hasImage: boolean
|
|
74
|
+
imageSizeBytes: number
|
|
75
|
+
} {
|
|
76
|
+
let systemPrompt = ''
|
|
77
|
+
let userPromptText = ''
|
|
78
|
+
let hasImage = false
|
|
79
|
+
let imageSizeBytes = 0
|
|
80
|
+
|
|
81
|
+
for (const msg of messages) {
|
|
82
|
+
if (typeof msg.content === 'string') {
|
|
83
|
+
if (msg.role === 'system') systemPrompt = msg.content
|
|
84
|
+
else userPromptText += msg.content
|
|
85
|
+
} else if (Array.isArray(msg.content)) {
|
|
86
|
+
for (const part of msg.content) {
|
|
87
|
+
if (part.type === 'text' && part.text) {
|
|
88
|
+
if (msg.role === 'system') systemPrompt = part.text
|
|
89
|
+
else userPromptText += part.text
|
|
90
|
+
}
|
|
91
|
+
if (part.type === 'image_url' && part.image_url?.url) {
|
|
92
|
+
hasImage = true
|
|
93
|
+
imageSizeBytes = part.image_url.url.length
|
|
94
|
+
}
|
|
95
|
+
if (part.type === 'audio' && part.audio?.data) {
|
|
96
|
+
imageSizeBytes += part.audio.data.length
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { systemPrompt, userPromptText, hasImage, imageSizeBytes }
|
|
103
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// @geenius-ai/shared — src/providers/elevenlabs.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ElevenLabs provider — dedicated TTS, voice cloning, and sound effects.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
AIProviderType,
|
|
9
|
+
AIGenerationResult,
|
|
10
|
+
AIGenerateTextOptions,
|
|
11
|
+
AIGenerateAudioOptions,
|
|
12
|
+
AIVoiceCloneOptions,
|
|
13
|
+
AIGenerateSoundEffectOptions,
|
|
14
|
+
} from '../types'
|
|
15
|
+
import type { AIProviderInterface } from './base'
|
|
16
|
+
|
|
17
|
+
export interface ElevenLabsConfig {
|
|
18
|
+
apiKey: string
|
|
19
|
+
baseUrl?: string
|
|
20
|
+
defaultModel?: string
|
|
21
|
+
defaultVoice?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class ElevenLabsProvider implements AIProviderInterface {
|
|
25
|
+
type: AIProviderType = 'elevenlabs'
|
|
26
|
+
name = 'ElevenLabs'
|
|
27
|
+
private apiKey: string
|
|
28
|
+
private baseUrl: string
|
|
29
|
+
private defaultModel: string
|
|
30
|
+
private defaultVoice: string
|
|
31
|
+
|
|
32
|
+
constructor(config: ElevenLabsConfig) {
|
|
33
|
+
this.apiKey = config.apiKey
|
|
34
|
+
this.baseUrl = (config.baseUrl ?? 'https://api.elevenlabs.io').replace(/\/$/, '')
|
|
35
|
+
this.defaultModel = config.defaultModel ?? 'eleven_multilingual_v2'
|
|
36
|
+
this.defaultVoice = config.defaultVoice ?? 'pNInz6obpgDQGcFmaJgB' // Adam
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async generateText(_options: AIGenerateTextOptions): Promise<AIGenerationResult> {
|
|
40
|
+
throw new Error('ElevenLabs does not support text generation. Use generateAudio instead.')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async generateAudio(options: AIGenerateAudioOptions): Promise<string> {
|
|
44
|
+
const voiceId = options.voice ?? this.defaultVoice
|
|
45
|
+
const response = await fetch(
|
|
46
|
+
`${this.baseUrl}/v1/text-to-speech/${voiceId}`,
|
|
47
|
+
{
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
'xi-api-key': this.apiKey,
|
|
52
|
+
'Accept': 'audio/mpeg',
|
|
53
|
+
},
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
model_id: options.model ?? this.defaultModel,
|
|
56
|
+
text: options.prompt,
|
|
57
|
+
voice_settings: {
|
|
58
|
+
stability: options.voiceSettings?.stability ?? 0.5,
|
|
59
|
+
similarity_boost: options.voiceSettings?.similarityBoost ?? 0.75,
|
|
60
|
+
style: options.voiceSettings?.style ?? 0.0,
|
|
61
|
+
use_speaker_boost: options.voiceSettings?.useSpeakerBoost ?? true,
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const errorText = await response.text()
|
|
69
|
+
throw new Error(`ElevenLabs TTS error (${response.status}): ${errorText}`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
73
|
+
const bytes = new Uint8Array(arrayBuffer)
|
|
74
|
+
let binary = ''
|
|
75
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
76
|
+
binary += String.fromCharCode(bytes[i]!)
|
|
77
|
+
}
|
|
78
|
+
return btoa(binary)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async cloneVoice(options: AIVoiceCloneOptions): Promise<string> {
|
|
82
|
+
const formData = new FormData()
|
|
83
|
+
formData.append('name', options.name)
|
|
84
|
+
if (options.description) formData.append('description', options.description)
|
|
85
|
+
|
|
86
|
+
for (let i = 0; i < options.samples.length; i++) {
|
|
87
|
+
const binaryStr = atob(options.samples[i]!)
|
|
88
|
+
const bytes = new Uint8Array(binaryStr.length)
|
|
89
|
+
for (let j = 0; j < binaryStr.length; j++) {
|
|
90
|
+
bytes[j] = binaryStr.charCodeAt(j)
|
|
91
|
+
}
|
|
92
|
+
const blob = new Blob([bytes], { type: 'audio/mp3' })
|
|
93
|
+
formData.append('files', blob, `sample_${i}.mp3`)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const response = await fetch(`${this.baseUrl}/v1/voices/add`, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: { 'xi-api-key': this.apiKey },
|
|
99
|
+
body: formData,
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
if (!response.ok) {
|
|
103
|
+
const errorText = await response.text()
|
|
104
|
+
throw new Error(`ElevenLabs voice clone error (${response.status}): ${errorText}`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const data = await response.json() as any
|
|
108
|
+
return data.voice_id
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async generateSoundEffect(options: AIGenerateSoundEffectOptions): Promise<string> {
|
|
112
|
+
const response = await fetch(`${this.baseUrl}/v1/sound-generation`, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
'xi-api-key': this.apiKey,
|
|
117
|
+
'Accept': 'audio/mpeg',
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
text: options.prompt,
|
|
121
|
+
duration_seconds: options.duration,
|
|
122
|
+
}),
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
const errorText = await response.text()
|
|
127
|
+
throw new Error(`ElevenLabs SFX error (${response.status}): ${errorText}`)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
131
|
+
const bytes = new Uint8Array(arrayBuffer)
|
|
132
|
+
let binary = ''
|
|
133
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
134
|
+
binary += String.fromCharCode(bytes[i]!)
|
|
135
|
+
}
|
|
136
|
+
return btoa(binary)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async listVoices(): Promise<Array<{ id: string; name: string; preview?: string }>> {
|
|
140
|
+
const response = await fetch(`${this.baseUrl}/v1/voices`, {
|
|
141
|
+
headers: { 'xi-api-key': this.apiKey },
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
throw new Error(`ElevenLabs list voices error (${response.status})`)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const data = await response.json() as any
|
|
149
|
+
return (data.voices ?? []).map((v: any) => ({
|
|
150
|
+
id: v.voice_id,
|
|
151
|
+
name: v.name,
|
|
152
|
+
preview: v.preview_url,
|
|
153
|
+
}))
|
|
154
|
+
}
|
|
155
|
+
}
|