Improve offline template loading

This commit is contained in:
boos
2026-06-01 11:02:36 +08:00
parent bb31118792
commit 04792bd3f7
4 changed files with 292 additions and 65 deletions
+26
View File
@@ -3650,6 +3650,32 @@ textarea {
background: color-mix(in srgb, var(--color-bg) 70%, var(--color-bg-card));
}
.picture-agent-template-placeholder {
width: 100%;
height: 102px;
display: grid;
place-items: center;
align-content: center;
gap: 4px;
border-radius: 6px;
background:
linear-gradient(135deg, color-mix(in srgb, var(--color-primary) 14%, transparent), transparent 56%),
color-mix(in srgb, var(--color-bg) 74%, var(--color-bg-card));
border: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent);
color: var(--color-text-primary);
}
.picture-agent-template-placeholder strong {
max-width: 100%;
font-size: 13px;
text-align: center;
}
.picture-agent-template-placeholder small {
color: var(--color-text-muted);
font-size: 11px;
}
.picture-agent-template-card span {
display: grid;
gap: 3px;
+11 -42
View File
@@ -57,7 +57,7 @@ type PromptTemplate = {
title: string;
tag: string;
size: string;
image: string;
image?: string | null;
prompt: string;
source?: {
name?: string;
@@ -76,7 +76,6 @@ type GalleryItem = {
};
const DEFAULT_PROMPT = 'A precise editorial product photo of a translucent glass robot painting a small neon city, sharp focus, clean background';
const TEMPLATE_GALLERY_JSON_URL = 'https://weiyyin.github.io/linux-do-gpt-image/linux_do_2036927_prompts_images.filtered.json';
const TEMPLATE_LIMIT = 144;
const QUALITY_OPTIONS = ['auto', 'low', 'medium', 'high'];
const ASPECT_OPTIONS = [
@@ -282,39 +281,6 @@ function isPictureModel(model: string) {
return !chatKeywords.some((keyword) => normalized.includes(keyword));
}
function normalizeGalleryItems(items: GalleryItem[], limit = TEMPLATE_LIMIT): PromptTemplate[] {
return items
.map<PromptTemplate | null>((item) => {
const prompt = (item.prompt || '').trim();
const image = (item.images || []).find((value) => value.startsWith('http'))
|| (item.image_host_url || '').trim();
if (Array.from(prompt).length < 20 || !image.startsWith('http')) return null;
return {
id: item.post_number ? `linux-do-${item.post_number}` : `linux-do-${templateTitle(prompt)}`,
title: templateTitle(prompt, item.post_number),
tag: templateTag(prompt),
size: templateSize(prompt),
image,
prompt,
source: {
name: 'Linux Do GPT Image Gallery',
url: 'https://weiyyin.github.io/linux-do-gpt-image/prompt_gallery.html',
postNumber: item.post_number,
username: item.username,
},
} satisfies PromptTemplate;
})
.filter((value): value is PromptTemplate => value !== null)
.slice(0, limit);
}
async function loadGalleryTemplatesDirectly(limit = TEMPLATE_LIMIT): Promise<PromptTemplate[]> {
const response = await fetch(TEMPLATE_GALLERY_JSON_URL, { cache: 'no-store' });
if (!response.ok) throw new Error(`gallery HTTP ${response.status}`);
const items = await response.json();
return normalizeGalleryItems(Array.isArray(items) ? items : [], limit);
}
export default function PictureAgent() {
const location = useLocation();
const audience: SessionAudience = location.pathname.startsWith('/user/') ? 'user' : 'admin';
@@ -424,11 +390,7 @@ export default function PictureAgent() {
const templatePayload = await templatesRes.json();
nextTemplates = Array.isArray(templatePayload?.templates) ? templatePayload.templates : [];
} else {
try {
nextTemplates = await loadGalleryTemplatesDirectly(TEMPLATE_LIMIT);
} catch {
setTemplatesError(await parseError(templatesRes));
}
setTemplatesError(await parseError(templatesRes));
}
let nextJobs: PictureJob[] = [];
if (jobsRes.ok) {
@@ -872,7 +834,7 @@ export default function PictureAgent() {
<div className="picture-agent-template-strip">
<div className="picture-agent-template-title">
<strong>参考模板</strong>
<span>{templatesLoading ? '正在刷新模板...' : '每次打开自动获取 Linux Do GPT Image Gallery'}</span>
<span>{templatesLoading ? '正在刷新模板...' : '内置模板优先,外部图库可用时自动补充'}</span>
</div>
<div className="picture-agent-template-list">
{templatesError && templates.length === 0 ? (
@@ -887,7 +849,14 @@ export default function PictureAgent() {
onClick={() => applyTemplate(template)}
title={template.prompt}
>
<img src={template.image} alt="" loading="lazy" referrerPolicy="no-referrer" />
{template.image ? (
<img src={template.image} alt="" loading="lazy" referrerPolicy="no-referrer" />
) : (
<div className="picture-agent-template-placeholder">
<strong>{template.tag}</strong>
<small>{template.size}</small>
</div>
)}
<span>
<strong>{template.title}</strong>
<em>{template.tag}{template.source?.postNumber ? ` · #${template.source.postNumber}` : ''}</em>