@promptbook/cli 0.104.0-5 → 0.104.0-7
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/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +3 -2
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +6 -2
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +15 -8
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/getAgentDefaultAvatarPrompt.ts +31 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +53 -38
- package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +6 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +200 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +3 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +3 -2
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +3 -2
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +3 -2
- package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +10 -2
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +8 -4
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +3 -1
- package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +48 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +11 -2
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +3 -1
- package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +49 -0
- package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +19 -0
- package/esm/index.es.js +8 -51
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +8 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +2 -0
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
- package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -3
- package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
- package/esm/typings/src/types/typeAliases.d.ts +11 -1
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +8 -51
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { AgentBasicInformation } from '@promptbook-local/types';
|
|
3
|
+
import { AgentBasicInformation, string_agent_name } from '@promptbook-local/types';
|
|
4
4
|
import { AgentProfile } from '../../../components/AgentProfile/AgentProfile';
|
|
5
5
|
import { AgentOptionsMenu } from './AgentOptionsMenu';
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ type AgentProfileWrapperProps = {
|
|
|
8
8
|
agent: AgentBasicInformation;
|
|
9
9
|
agentUrl: string;
|
|
10
10
|
agentEmail: string;
|
|
11
|
-
agentName:
|
|
11
|
+
agentName: string_agent_name;
|
|
12
12
|
brandColorHex: string;
|
|
13
13
|
isAdmin: boolean;
|
|
14
14
|
isHeadless: boolean;
|
|
@@ -27,6 +27,7 @@ export function AgentProfileWrapper(props: AgentProfileWrapperProps) {
|
|
|
27
27
|
<AgentProfile
|
|
28
28
|
agent={agent}
|
|
29
29
|
agentUrl={agentUrl}
|
|
30
|
+
permanentId={permanentId || agentName}
|
|
30
31
|
agentEmail={agentEmail}
|
|
31
32
|
isHeadless={isHeadless}
|
|
32
33
|
renderMenu={({ onShowQrCode }) => (
|
|
@@ -13,7 +13,11 @@ export async function getAgentName(params: Promise<{ agentName: string }>) {
|
|
|
13
13
|
export async function getAgentProfile(agentName: string) {
|
|
14
14
|
const collection = await $provideAgentCollectionForServer();
|
|
15
15
|
const agentSource = await collection.getAgentSource(agentName);
|
|
16
|
-
|
|
16
|
+
const agentProfile = parseAgentSource(agentSource);
|
|
17
|
+
|
|
18
|
+
console.log('!!!!', { agentSource, agentProfile });
|
|
19
|
+
|
|
20
|
+
return agentProfile;
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
export async function isAgentDeleted(agentName: string): Promise<boolean> {
|
|
@@ -33,5 +37,5 @@ export async function isAgentDeleted(agentName: string): Promise<boolean> {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
/**
|
|
36
|
-
* TODO: Split to multiple files
|
|
40
|
+
* TODO: Split to multiple files, refactor
|
|
37
41
|
*/
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
3
4
|
import Editor from '@monaco-editor/react';
|
|
5
|
+
import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
|
|
6
|
+
import { AgentBasicInformation } from '@promptbook-local/types';
|
|
4
7
|
import { ArrowLeftIcon, ChevronDownIcon, CodeIcon } from 'lucide-react';
|
|
5
8
|
import Link from 'next/link';
|
|
6
9
|
import { useCallback, useEffect, useState } from 'react';
|
|
@@ -29,7 +32,7 @@ function getLanguageFromTranspiler(transpilerName?: string): string {
|
|
|
29
32
|
|
|
30
33
|
export default function AgentCodePage({ params }: { params: Promise<{ agentName: string }> }) {
|
|
31
34
|
const [agentName, setAgentName] = useState<string>('');
|
|
32
|
-
const [agentProfile, setAgentProfile] = useState<
|
|
35
|
+
const [agentProfile, setAgentProfile] = useState<AgentBasicInformation | null>(null);
|
|
33
36
|
const [transpilers, setTranspilers] = useState<Transpiler[]>([]);
|
|
34
37
|
const [selectedTranspiler, setSelectedTranspiler] = useState<Transpiler | null>(null);
|
|
35
38
|
const [transpiledCode, setTranspiledCode] = useState<string>('');
|
|
@@ -114,13 +117,17 @@ export default function AgentCodePage({ params }: { params: Promise<{ agentName:
|
|
|
114
117
|
{/* Header */}
|
|
115
118
|
<div className="p-6 border-b border-gray-200 flex items-center gap-4">
|
|
116
119
|
{/* eslint-disable @typescript-eslint/no-explicit-any, @next/next/no-img-element */}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
|
|
121
|
+
<img
|
|
122
|
+
src={
|
|
123
|
+
agentProfile.meta.image ||
|
|
124
|
+
agentProfile.permanentId ||
|
|
125
|
+
generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)
|
|
126
|
+
}
|
|
127
|
+
alt={agentProfile.meta.fullname || agentName}
|
|
128
|
+
className="w-16 h-16 rounded-full object-cover border-2 border-gray-200"
|
|
129
|
+
/>
|
|
130
|
+
|
|
124
131
|
<div className="flex-1">
|
|
125
132
|
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
|
|
126
133
|
<h1 className="text-2xl font-bold text-gray-900">
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AgentBasicInformation } from '@promptbook-local/types';
|
|
2
|
+
import spaceTrim from 'spacetrim';
|
|
3
|
+
import { string_prompt_image } from '../../../../../../../../src/types/typeAliases';
|
|
4
|
+
|
|
5
|
+
export function getAgentDefaultAvatarPrompt(agent: AgentBasicInformation): string_prompt_image {
|
|
6
|
+
const {
|
|
7
|
+
agentName,
|
|
8
|
+
personaDescription,
|
|
9
|
+
meta: { fullname, color },
|
|
10
|
+
} = agent;
|
|
11
|
+
|
|
12
|
+
return spaceTrim(
|
|
13
|
+
(block) => `
|
|
14
|
+
Professional corporate headshot of ${fullname || agentName}
|
|
15
|
+
|
|
16
|
+
${block(personaDescription || '')}
|
|
17
|
+
|
|
18
|
+
- Professional business portrait photograph
|
|
19
|
+
- Photorealistic, studio quality lighting
|
|
20
|
+
- Shot with 85mm lens, shallow depth of field
|
|
21
|
+
- Neutral gray or soft gradient background
|
|
22
|
+
- Subject wearing professional attire with accent colors: ${color}
|
|
23
|
+
- Confident, approachable expression with slight smile
|
|
24
|
+
- Eye-level camera angle, centered composition
|
|
25
|
+
- Soft diffused lighting, subtle rim light
|
|
26
|
+
- Sharp focus on eyes, cinematic color grading
|
|
27
|
+
- 8K resolution, ultra detailed
|
|
28
|
+
|
|
29
|
+
`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -4,12 +4,13 @@ import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentColle
|
|
|
4
4
|
import { $provideCdnForServer } from '@/src/tools/$provideCdnForServer';
|
|
5
5
|
import { $provideExecutionToolsForServer } from '@/src/tools/$provideExecutionToolsForServer';
|
|
6
6
|
import { parseAgentSource } from '@promptbook-local/core';
|
|
7
|
-
import { serializeError } from '@promptbook-local/utils';
|
|
7
|
+
import { computeHash, serializeError } from '@promptbook-local/utils';
|
|
8
8
|
import { NextRequest, NextResponse } from 'next/server';
|
|
9
9
|
import { assertsError } from '../../../../../../../../src/errors/assertsError';
|
|
10
|
-
import { getSingleLlmExecutionTools } from '../../../../../../../../src/llm-providers/_multiple/getSingleLlmExecutionTools';
|
|
11
10
|
import type { LlmExecutionTools } from '../../../../../../../../src/execution/LlmExecutionTools';
|
|
11
|
+
import { getSingleLlmExecutionTools } from '../../../../../../../../src/llm-providers/_multiple/getSingleLlmExecutionTools';
|
|
12
12
|
import type { string_url } from '../../../../../../../../src/types/typeAliases';
|
|
13
|
+
import { getAgentDefaultAvatarPrompt } from './getAgentDefaultAvatarPrompt';
|
|
13
14
|
|
|
14
15
|
export async function GET(request: NextRequest, { params }: { params: Promise<{ agentName: string }> }) {
|
|
15
16
|
try {
|
|
@@ -20,13 +21,28 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
20
21
|
return NextResponse.json({ error: 'Agent name is required' }, { status: 400 });
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
// 1. Fetch agent data first to construct the prompt
|
|
25
|
+
const collection = await $provideAgentCollectionForServer();
|
|
26
|
+
let agentSource;
|
|
27
|
+
try {
|
|
28
|
+
agentSource = await collection.getAgentSource(agentName);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
// If agent not found, redirect to pravatar with the agent name as unique identifier
|
|
31
|
+
const pravaratUrl = `https://i.pravatar.cc/1024?u=${encodeURIComponent(agentName)}`;
|
|
32
|
+
return NextResponse.redirect(pravaratUrl);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const agentProfile = parseAgentSource(agentSource);
|
|
36
|
+
|
|
37
|
+
const prompt = getAgentDefaultAvatarPrompt(agentProfile);
|
|
38
|
+
|
|
39
|
+
// Use hash of the prompt as cache key - this ensures regeneration when prompt changes
|
|
40
|
+
const promptHash = computeHash(prompt);
|
|
41
|
+
const internalFilename = `agent-avatar-${promptHash}.png`;
|
|
26
42
|
|
|
27
43
|
const supabase = $provideSupabaseForServer();
|
|
28
44
|
|
|
29
|
-
// Check if image already exists in database
|
|
45
|
+
// Check if image with this prompt hash already exists in database
|
|
30
46
|
const { data: existingImage, error: selectError } = await supabase
|
|
31
47
|
.from(await $getTableName(`Image`))
|
|
32
48
|
.select('cdnUrl')
|
|
@@ -39,35 +55,23 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
39
55
|
}
|
|
40
56
|
|
|
41
57
|
if (existingImage) {
|
|
42
|
-
// Image exists,
|
|
43
|
-
|
|
58
|
+
// Image exists, fetch from CDN and return directly
|
|
59
|
+
const imageResponse = await fetch(existingImage.cdnUrl as string_url);
|
|
60
|
+
if (!imageResponse.ok) {
|
|
61
|
+
throw new Error(`Failed to fetch image from CDN: ${imageResponse.status}`);
|
|
62
|
+
}
|
|
63
|
+
const imageBuffer = await imageResponse.arrayBuffer();
|
|
64
|
+
return new NextResponse(imageBuffer, {
|
|
65
|
+
status: 200,
|
|
66
|
+
headers: {
|
|
67
|
+
'Content-Type': 'image/png',
|
|
68
|
+
'Cache-Control': 'public, max-age=31536000, immutable',
|
|
69
|
+
},
|
|
70
|
+
});
|
|
44
71
|
}
|
|
45
72
|
|
|
46
73
|
// Image doesn't exist, generate it
|
|
47
74
|
|
|
48
|
-
// 1. Fetch agent data
|
|
49
|
-
const collection = await $provideAgentCollectionForServer();
|
|
50
|
-
let agentSource;
|
|
51
|
-
try {
|
|
52
|
-
agentSource = await collection.getAgentSource(agentName);
|
|
53
|
-
} catch (error) {
|
|
54
|
-
// If agent not found, return 404 or default generic image?
|
|
55
|
-
// User said: "Use the ... instead of Gravatar for agents that do not have custom uploaded avatar"
|
|
56
|
-
// If agent doesn't exist, we probably can't generate a specific avatar.
|
|
57
|
-
return NextResponse.json({ error: 'Agent not found' }, { status: 404 });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const agentProfile = parseAgentSource(agentSource);
|
|
61
|
-
|
|
62
|
-
// Extract required fields
|
|
63
|
-
const name = agentProfile.meta?.title || agentProfile.agentName || agentName;
|
|
64
|
-
const persona = agentProfile.personaDescription || 'an AI agent';
|
|
65
|
-
const color = agentProfile.meta?.color || 'blue';
|
|
66
|
-
|
|
67
|
-
// Construct prompt
|
|
68
|
-
// "Image of {agent.name}, {agent.persona}, portrait, use color ${agent.meta.color}, detailed, high quality"
|
|
69
|
-
const prompt = `Image of ${name}, ${persona}, portrait, use color ${color}, detailed, high quality`;
|
|
70
|
-
|
|
71
75
|
// 2. Generate image
|
|
72
76
|
const executionTools = await $provideExecutionToolsForServer();
|
|
73
77
|
const llmTools = getSingleLlmExecutionTools(executionTools.llm) as LlmExecutionTools;
|
|
@@ -79,12 +83,13 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
79
83
|
const imageResult = await llmTools.callImageGenerationModel({
|
|
80
84
|
title: `Generate default avatar for ${agentName}`,
|
|
81
85
|
content: prompt,
|
|
82
|
-
parameters: {
|
|
83
|
-
size: '1024x1792', // Vertical orientation
|
|
84
|
-
},
|
|
86
|
+
parameters: {},
|
|
85
87
|
modelRequirements: {
|
|
86
88
|
modelVariant: 'IMAGE_GENERATION',
|
|
87
|
-
modelName: 'dall-e-3',
|
|
89
|
+
modelName: 'dall-e-3',
|
|
90
|
+
size: '1024x1792', // <- Vertical orientation
|
|
91
|
+
quality: 'hd',
|
|
92
|
+
style: 'natural',
|
|
88
93
|
},
|
|
89
94
|
});
|
|
90
95
|
|
|
@@ -125,9 +130,19 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|
|
125
130
|
throw insertError;
|
|
126
131
|
}
|
|
127
132
|
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
// Return the newly created image directly
|
|
134
|
+
const finalImageResponse = await fetch(cdnUrl.href);
|
|
135
|
+
if (!finalImageResponse.ok) {
|
|
136
|
+
throw new Error(`Failed to fetch newly created image from CDN: ${finalImageResponse.status}`);
|
|
137
|
+
}
|
|
138
|
+
const finalImageBuffer = await finalImageResponse.arrayBuffer();
|
|
139
|
+
return new NextResponse(finalImageBuffer, {
|
|
140
|
+
status: 200,
|
|
141
|
+
headers: {
|
|
142
|
+
'Content-Type': 'image/png',
|
|
143
|
+
'Cache-Control': 'public, max-age=31536000, immutable',
|
|
144
|
+
},
|
|
145
|
+
});
|
|
131
146
|
} catch (error) {
|
|
132
147
|
assertsError(error);
|
|
133
148
|
console.error('Error serving default avatar:', error);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
1
|
+
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
2
2
|
import { serializeError } from '@promptbook-local/utils';
|
|
3
3
|
import { ImageResponse } from 'next/og';
|
|
4
4
|
import { assertsError } from '../../../../../../../../src/errors/assertsError';
|
|
5
5
|
import { Color } from '../../../../../../../../src/utils/color/Color';
|
|
6
6
|
import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
|
|
7
7
|
import { getAgentName, getAgentProfile } from '../../_utils';
|
|
8
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
8
9
|
|
|
9
10
|
const size = {
|
|
10
11
|
width: 256,
|
|
@@ -45,7 +46,10 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
45
46
|
>
|
|
46
47
|
{/* Note: `next/image` is not working propperly with `next/og` */}
|
|
47
48
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
48
|
-
<img
|
|
49
|
+
<img
|
|
50
|
+
src={agentProfile.meta.image || agentProfile.permanentId ||generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)}
|
|
51
|
+
alt="Agent Icon"
|
|
52
|
+
/>
|
|
49
53
|
</div>
|
|
50
54
|
</div>
|
|
51
55
|
),
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { saturate } from '@promptbook-local/color';
|
|
4
|
+
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
5
|
+
import Link from 'next/link';
|
|
6
|
+
import { Color } from '../../../../../../../src/utils/color/Color';
|
|
7
|
+
import { getAgentName, getAgentProfile } from '../_utils';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Available image types for agents with their descriptions and sizes
|
|
11
|
+
*/
|
|
12
|
+
const AGENT_IMAGES = [
|
|
13
|
+
{
|
|
14
|
+
name: 'default-avatar.png',
|
|
15
|
+
title: 'Default Avatar',
|
|
16
|
+
description: 'AI-generated avatar image based on the agent profile. Vertical orientation (1024x1792).',
|
|
17
|
+
size: '1024×1792',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'icon-256.png',
|
|
21
|
+
title: 'Icon (256×256)',
|
|
22
|
+
description: 'Small circular icon suitable for profile pictures and thumbnails.',
|
|
23
|
+
size: '256×256',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'screenshot-fullhd.png',
|
|
27
|
+
title: 'Screenshot Full HD',
|
|
28
|
+
description: 'Landscape screenshot showing the agent with name. Suitable for desktop previews.',
|
|
29
|
+
size: '1920×1080',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'screenshot-phone.png',
|
|
33
|
+
title: 'Screenshot Phone',
|
|
34
|
+
description: 'Portrait screenshot optimized for mobile devices.',
|
|
35
|
+
size: '1080×1920',
|
|
36
|
+
},
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
export default async function AgentImagesPage({ params }: { params: Promise<{ agentName: string }> }) {
|
|
40
|
+
const agentName = await getAgentName(params);
|
|
41
|
+
const agentProfile = await getAgentProfile(agentName);
|
|
42
|
+
|
|
43
|
+
const brandColor = Color.fromSafe(agentProfile.meta.color || PROMPTBOOK_COLOR);
|
|
44
|
+
const brandColorHex = brandColor.then(saturate(-0.5)).toHex();
|
|
45
|
+
|
|
46
|
+
const fullname = (agentProfile.meta.fullname || agentProfile.agentName || 'Agent') as string;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
style={{
|
|
51
|
+
minHeight: '100vh',
|
|
52
|
+
backgroundColor: '#f5f5f5',
|
|
53
|
+
padding: '2rem',
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
56
|
+
<div
|
|
57
|
+
style={{
|
|
58
|
+
maxWidth: '1200px',
|
|
59
|
+
margin: '0 auto',
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
<header
|
|
63
|
+
style={{
|
|
64
|
+
marginBottom: '2rem',
|
|
65
|
+
padding: '1.5rem',
|
|
66
|
+
backgroundColor: brandColorHex,
|
|
67
|
+
borderRadius: '12px',
|
|
68
|
+
color: 'white',
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<h1 style={{ margin: 0, fontSize: '2rem' }}>
|
|
72
|
+
Images for <strong>{fullname}</strong>
|
|
73
|
+
</h1>
|
|
74
|
+
<p style={{ margin: '0.5rem 0 0', opacity: 0.9 }}>
|
|
75
|
+
All available image assets for agent{' '}
|
|
76
|
+
<code
|
|
77
|
+
style={{
|
|
78
|
+
backgroundColor: 'rgba(255,255,255,0.2)',
|
|
79
|
+
padding: '2px 6px',
|
|
80
|
+
borderRadius: '4px',
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
{agentName}
|
|
84
|
+
</code>
|
|
85
|
+
</p>
|
|
86
|
+
</header>
|
|
87
|
+
|
|
88
|
+
<div
|
|
89
|
+
style={{
|
|
90
|
+
display: 'grid',
|
|
91
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
|
|
92
|
+
gap: '1.5rem',
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{AGENT_IMAGES.map((image) => {
|
|
96
|
+
const imageUrl = `/agents/${encodeURIComponent(agentName)}/images/${image.name}`;
|
|
97
|
+
return (
|
|
98
|
+
<div
|
|
99
|
+
key={image.name}
|
|
100
|
+
style={{
|
|
101
|
+
backgroundColor: 'white',
|
|
102
|
+
borderRadius: '12px',
|
|
103
|
+
overflow: 'hidden',
|
|
104
|
+
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
|
105
|
+
}}
|
|
106
|
+
>
|
|
107
|
+
<div
|
|
108
|
+
style={{
|
|
109
|
+
aspectRatio: '16/9',
|
|
110
|
+
backgroundColor: '#e0e0e0',
|
|
111
|
+
display: 'flex',
|
|
112
|
+
alignItems: 'center',
|
|
113
|
+
justifyContent: 'center',
|
|
114
|
+
overflow: 'hidden',
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
118
|
+
<img
|
|
119
|
+
src={imageUrl}
|
|
120
|
+
alt={image.title}
|
|
121
|
+
style={{
|
|
122
|
+
maxWidth: '100%',
|
|
123
|
+
maxHeight: '100%',
|
|
124
|
+
objectFit: 'contain',
|
|
125
|
+
}}
|
|
126
|
+
/>
|
|
127
|
+
</div>
|
|
128
|
+
<div style={{ padding: '1rem' }}>
|
|
129
|
+
<h2 style={{ margin: '0 0 0.5rem', fontSize: '1.25rem' }}>{image.title}</h2>
|
|
130
|
+
<p style={{ margin: '0 0 0.5rem', color: '#666', fontSize: '0.9rem' }}>
|
|
131
|
+
{image.description}
|
|
132
|
+
</p>
|
|
133
|
+
<div
|
|
134
|
+
style={{
|
|
135
|
+
display: 'flex',
|
|
136
|
+
justifyContent: 'space-between',
|
|
137
|
+
alignItems: 'center',
|
|
138
|
+
marginTop: '1rem',
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
<span
|
|
142
|
+
style={{
|
|
143
|
+
backgroundColor: '#f0f0f0',
|
|
144
|
+
padding: '4px 8px',
|
|
145
|
+
borderRadius: '4px',
|
|
146
|
+
fontSize: '0.85rem',
|
|
147
|
+
color: '#555',
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
{image.size}
|
|
151
|
+
</span>
|
|
152
|
+
<Link
|
|
153
|
+
href={imageUrl}
|
|
154
|
+
target="_blank"
|
|
155
|
+
style={{
|
|
156
|
+
backgroundColor: brandColorHex,
|
|
157
|
+
color: 'white',
|
|
158
|
+
padding: '8px 16px',
|
|
159
|
+
borderRadius: '6px',
|
|
160
|
+
textDecoration: 'none',
|
|
161
|
+
fontSize: '0.9rem',
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
Open Image
|
|
165
|
+
</Link>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
})}
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<footer
|
|
174
|
+
style={{
|
|
175
|
+
marginTop: '2rem',
|
|
176
|
+
padding: '1rem',
|
|
177
|
+
backgroundColor: 'white',
|
|
178
|
+
borderRadius: '12px',
|
|
179
|
+
textAlign: 'center',
|
|
180
|
+
color: '#666',
|
|
181
|
+
}}
|
|
182
|
+
>
|
|
183
|
+
<p style={{ margin: 0 }}>
|
|
184
|
+
<Link
|
|
185
|
+
href={`/agents/${encodeURIComponent(agentName)}`}
|
|
186
|
+
style={{ color: brandColorHex, textDecoration: 'none' }}
|
|
187
|
+
>
|
|
188
|
+
← Back to {fullname}
|
|
189
|
+
</Link>
|
|
190
|
+
</p>
|
|
191
|
+
</footer>
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* TODO: [🦚] Add download button functionality
|
|
199
|
+
* TODO: [🦚] Add image regeneration option for default-avatar
|
|
200
|
+
*/
|
package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
1
|
+
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
2
2
|
import { serializeError } from '@promptbook-local/utils';
|
|
3
3
|
import { ImageResponse } from 'next/og';
|
|
4
4
|
import { assertsError } from '../../../../../../../../src/errors/assertsError';
|
|
@@ -7,6 +7,7 @@ import { textColor } from '../../../../../../../../src/utils/color/operators/fur
|
|
|
7
7
|
import { grayscale } from '../../../../../../../../src/utils/color/operators/grayscale';
|
|
8
8
|
import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
|
|
9
9
|
import { getAgentName, getAgentProfile } from '../../_utils';
|
|
10
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
10
11
|
|
|
11
12
|
const size = {
|
|
12
13
|
width: 1920,
|
|
@@ -51,7 +52,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
51
52
|
backgroundColor: agentColor.toHex(),
|
|
52
53
|
borderRadius: '50%',
|
|
53
54
|
}}
|
|
54
|
-
src={agentProfile.meta.image
|
|
55
|
+
src={agentProfile.meta.image || agentProfile.permanentId ||generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)}
|
|
55
56
|
alt="Agent Icon"
|
|
56
57
|
/>
|
|
57
58
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
1
|
+
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
2
2
|
import { serializeError } from '@promptbook-local/utils';
|
|
3
3
|
import { ImageResponse } from 'next/og';
|
|
4
4
|
import { assertsError } from '../../../../../../../../src/errors/assertsError';
|
|
@@ -7,6 +7,7 @@ import { textColor } from '../../../../../../../../src/utils/color/operators/fur
|
|
|
7
7
|
import { grayscale } from '../../../../../../../../src/utils/color/operators/grayscale';
|
|
8
8
|
import { keepUnused } from '../../../../../../../../src/utils/organization/keepUnused';
|
|
9
9
|
import { getAgentName, getAgentProfile } from '../../_utils';
|
|
10
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
10
11
|
|
|
11
12
|
const size = {
|
|
12
13
|
width: 1080,
|
|
@@ -51,7 +52,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ agen
|
|
|
51
52
|
backgroundColor: agentColor.toHex(),
|
|
52
53
|
borderRadius: '50%',
|
|
53
54
|
}}
|
|
54
|
-
src={agentProfile.meta.image
|
|
55
|
+
src={agentProfile.meta.image || agentProfile.permanentId ||generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)}
|
|
55
56
|
alt="Agent Icon"
|
|
56
57
|
/>
|
|
57
58
|
</div>
|
|
@@ -4,7 +4,7 @@ import { $getTableName } from '@/src/database/$getTableName';
|
|
|
4
4
|
import { $provideSupabase } from '@/src/database/$provideSupabase';
|
|
5
5
|
import { $provideServer } from '@/src/tools/$provideServer';
|
|
6
6
|
import { isUserAdmin } from '@/src/utils/isUserAdmin';
|
|
7
|
-
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
7
|
+
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
8
8
|
import { ArrowLeftIcon, BoxIcon, CodeIcon, GlobeIcon, ServerIcon, TerminalIcon } from 'lucide-react';
|
|
9
9
|
import { headers } from 'next/headers';
|
|
10
10
|
import Link from 'next/link';
|
|
@@ -20,6 +20,7 @@ import { CopyField } from '../CopyField';
|
|
|
20
20
|
import { generateAgentMetadata } from '../generateAgentMetadata';
|
|
21
21
|
import { SdkCodeTabs } from './SdkCodeTabs';
|
|
22
22
|
import { WebsiteIntegrationTabs } from './WebsiteIntegrationTabs';
|
|
23
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
23
24
|
|
|
24
25
|
export const generateMetadata = generateAgentMetadata;
|
|
25
26
|
|
|
@@ -187,7 +188,7 @@ export default async function AgentIntegrationPage({ params }: { params: Promise
|
|
|
187
188
|
{agentProfile.meta.image && (
|
|
188
189
|
// eslint-disable-next-line @next/next/no-img-element
|
|
189
190
|
<img
|
|
190
|
-
src={agentProfile.meta.image
|
|
191
|
+
src={agentProfile.meta.image || agentProfile.permanentId ||generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)}
|
|
191
192
|
alt={agentProfile.meta.fullname || agentName}
|
|
192
193
|
className="w-16 h-16 rounded-full object-cover border-2"
|
|
193
194
|
style={{ borderColor: primaryColor }}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use server';
|
|
2
2
|
|
|
3
3
|
import { $provideServer } from '@/src/tools/$provideServer';
|
|
4
|
-
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
4
|
+
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
5
5
|
import { ArrowLeftIcon, CodeIcon, HomeIcon, LinkIcon, ShareIcon } from 'lucide-react';
|
|
6
6
|
import { headers } from 'next/headers';
|
|
7
7
|
import Link from 'next/link';
|
|
@@ -13,6 +13,7 @@ import { getAgentName, getAgentProfile } from '../_utils';
|
|
|
13
13
|
import { getAgentExternalLinks, getAgentLinks } from '../agentLinks';
|
|
14
14
|
import { CopyField } from '../CopyField';
|
|
15
15
|
import { generateAgentMetadata } from '../generateAgentMetadata';
|
|
16
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
16
17
|
|
|
17
18
|
export const generateMetadata = generateAgentMetadata;
|
|
18
19
|
|
|
@@ -56,7 +57,7 @@ export default async function AgentLinksPage({ params }: { params: Promise<{ age
|
|
|
56
57
|
{agentProfile.meta.image && (
|
|
57
58
|
// eslint-disable-next-line @next/next/no-img-element
|
|
58
59
|
<img
|
|
59
|
-
src={agentProfile.meta.image
|
|
60
|
+
src={agentProfile.meta.image || agentProfile.permanentId || generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)}
|
|
60
61
|
alt={agentProfile.meta.fullname || agentName}
|
|
61
62
|
className="w-16 h-16 rounded-full object-cover border-2"
|
|
62
63
|
style={{ borderColor: primaryColor }}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
2
|
+
import { generatePlaceholderAgentProfileImageUrl, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
2
3
|
import { serializeError } from '@promptbook-local/utils';
|
|
3
4
|
import { ImageResponse } from 'next/og';
|
|
4
5
|
import { assertsError } from '../../../../../../src/errors/assertsError';
|
|
@@ -54,7 +55,14 @@ export default async function Image({ params }: { params: Promise<{ agentName: s
|
|
|
54
55
|
backgroundColor: agentColor.toHex(),
|
|
55
56
|
borderRadius: '50%',
|
|
56
57
|
}}
|
|
57
|
-
src={
|
|
58
|
+
src={
|
|
59
|
+
agentProfile.meta.image ||
|
|
60
|
+
agentProfile.permanentId ||
|
|
61
|
+
generatePlaceholderAgentProfileImageUrl(
|
|
62
|
+
agentProfile.permanentId || agentName,
|
|
63
|
+
NEXT_PUBLIC_SITE_URL,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
58
66
|
alt="Agent Icon"
|
|
59
67
|
/>
|
|
60
68
|
</div>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
'use server';
|
|
2
2
|
|
|
3
|
+
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
3
4
|
import { $provideServer } from '@/src/tools/$provideServer';
|
|
4
5
|
import { isUserAdmin } from '@/src/utils/isUserAdmin';
|
|
5
6
|
import { saturate } from '@promptbook-local/color';
|
|
6
|
-
import { PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
7
|
-
import { NotFoundError } from '@promptbook-local/core';
|
|
7
|
+
import { generatePlaceholderAgentProfileImageUrl, NotFoundError, PROMPTBOOK_COLOR } from '@promptbook-local/core';
|
|
8
8
|
import { notFound } from 'next/navigation';
|
|
9
9
|
import { Color } from '../../../../../../src/utils/color/Color';
|
|
10
|
+
import { DeletedAgentBanner } from '../../../components/DeletedAgentBanner';
|
|
10
11
|
import { getAgentName, getAgentProfile, isAgentDeleted } from './_utils';
|
|
11
12
|
import { getAgentLinks } from './agentLinks';
|
|
12
13
|
import { AgentProfileChat } from './AgentProfileChat';
|
|
13
14
|
import { AgentProfileWrapper } from './AgentProfileWrapper';
|
|
14
15
|
import { generateAgentMetadata } from './generateAgentMetadata';
|
|
15
16
|
import { ServiceWorkerRegister } from './ServiceWorkerRegister';
|
|
16
|
-
import { DeletedAgentBanner } from '../../../components/DeletedAgentBanner';
|
|
17
17
|
|
|
18
18
|
export const generateMetadata = generateAgentMetadata;
|
|
19
19
|
|
|
@@ -96,7 +96,11 @@ export default async function AgentPage({
|
|
|
96
96
|
agentName={agentName}
|
|
97
97
|
fullname={fullname}
|
|
98
98
|
brandColorHex={brandColorHex}
|
|
99
|
-
avatarSrc={
|
|
99
|
+
avatarSrc={
|
|
100
|
+
agentProfile.meta.image ||
|
|
101
|
+
agentProfile.permanentId ||
|
|
102
|
+
generatePlaceholderAgentProfileImageUrl(agentName, NEXT_PUBLIC_SITE_URL)
|
|
103
|
+
}
|
|
100
104
|
isDeleted={isDeleted}
|
|
101
105
|
/>
|
|
102
106
|
</AgentProfileWrapper>
|