mirror of
https://github.com/discourse/discourse.git
synced 2026-08-08 16:57:36 +08:00
### settings Settings required for V2 captions: - discourse_ai_enabled = true - ai_post_image_descriptions_enabled = true - ai_helper_image_caption_agent must be set. It defaults to -26, the default image caption agent `+` optional tuning: - ai_post_image_descriptions_per_post_limit, default 10 - ai_post_image_descriptions_backfill_hourly_rate, default 0, so backfill is off by default - ai_post_image_descriptions_backfill_max_age_days, default 30 These settings are required for generation/backfill: - the selected `ai_helper_image_caption_agent` must exist and be enabled - the agent/persona must be vision-enabled - the resolved LLM must be vision-capable - credits must be available - ai_post_image_descriptions_backfill_hourly_rate > 0 for scheduled backfill ______ ### this pr ... does _a few things_. 1. removes the old AI image captioning flow (v1)... - removes the composer manual captioning UI - stops inserting generated captions into post raw - removes `image_caption` from the AI helper enabled features setting 2. adds the new post image description flow (v2)... - backfills descriptions for existing post images - stores descriptions in `ai_post_image_descriptions`, keyed by `post_id`, `locale`, and `base62_sha1` - keeps duplicate rows per post image instead of relying only on uploads - cook-time lookup, deletion, and per-post editing stay simple even when multiple posts reuse the same upload - doing this also prevents the author of one post image from affecting another post's image if they have the same image - uses `base62_sha1` and `locale` for reuse when the same image appears again - exposes caption editing from the composer preview for already-described post images - includes descriptions in search indexing without inserting them into raw - decorates cooked post images with localized `aria-description` - shows the AI description visibly in the lightbox under the existing image title
259 lines
4.6 KiB
SCSS
Vendored
259 lines
4.6 KiB
SCSS
Vendored
.d-lazyload-hidden {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.onebox img.d-lazyload-hidden:not(.ytp-thumbnail-image) {
|
|
border: 1px solid var(--content-border-color);
|
|
}
|
|
|
|
.cooked img.d-lazyload:not(.animated) {
|
|
transition: opacity 0.4s 0.75s ease;
|
|
}
|
|
|
|
.lightbox-wrapper {
|
|
display: inline-block;
|
|
vertical-align: middle;
|
|
|
|
img {
|
|
object-fit: cover;
|
|
object-position: top;
|
|
}
|
|
|
|
&,
|
|
* {
|
|
outline: 0;
|
|
}
|
|
|
|
.lightbox {
|
|
position: relative;
|
|
display: inline-block;
|
|
overflow: hidden;
|
|
|
|
&:hover .meta {
|
|
user-select: none;
|
|
opacity: 0.9;
|
|
transition: opacity 0.5s;
|
|
}
|
|
|
|
.meta {
|
|
--meta-element-margin: 0.375em;
|
|
position: absolute;
|
|
bottom: 0;
|
|
width: 100%;
|
|
color: var(--secondary);
|
|
background: var(--primary);
|
|
opacity: 0;
|
|
transition: opacity 0.2s;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
@media (pointer: coarse) {
|
|
align-items: center;
|
|
background: var(--secondary);
|
|
color: var(--primary-high);
|
|
height: 25px;
|
|
width: 25px;
|
|
bottom: 0;
|
|
right: 0;
|
|
opacity: 0.8;
|
|
transition: opacity 500ms;
|
|
|
|
&.open {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.filename {
|
|
margin: var(--meta-element-margin);
|
|
|
|
@include ellipsis;
|
|
|
|
@media (pointer: coarse) {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.d-icon {
|
|
margin: var(--meta-element-margin);
|
|
opacity: 0.8;
|
|
color: var(--secondary);
|
|
|
|
+ .filename {
|
|
margin-left: 0;
|
|
}
|
|
|
|
&.d-icon-far-image {
|
|
@media (pointer: coarse) {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.informations {
|
|
margin: var(--meta-element-margin);
|
|
padding-right: 20px;
|
|
color: var(--secondary-high);
|
|
font-size: var(--font-0);
|
|
flex-shrink: 0;
|
|
flex-grow: 3;
|
|
|
|
@media (pointer: coarse) {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
@media (pointer: coarse) {
|
|
.d-icon-discourse-expand {
|
|
color: var(--primary-high);
|
|
}
|
|
}
|
|
}
|
|
|
|
.discourse-no-touch {
|
|
a.lightbox {
|
|
transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
|
|
}
|
|
|
|
a.lightbox:hover {
|
|
box-shadow:
|
|
0 2px 5px 0 rgb(var(--always-black-rgb), 0.2),
|
|
0 2px 10px 0 rgb(var(--always-black-rgb), 0.2);
|
|
}
|
|
}
|
|
|
|
.rtl {
|
|
.pswp__scroll-wrap,
|
|
.pswp__bg,
|
|
.pswp__container,
|
|
.pswp__item,
|
|
.pswp__content,
|
|
.pswp__img,
|
|
.pswp__zoom-wrap {
|
|
right: 0;
|
|
left: unset;
|
|
}
|
|
|
|
.pswp .pswp__top-bar .pswp__button .pswp__icn {
|
|
right: 6px;
|
|
left: unset;
|
|
}
|
|
|
|
.pswp__button--arrow--next {
|
|
left: 0 !important;
|
|
right: unset !important;
|
|
|
|
.pswp__icn {
|
|
right: unset;
|
|
left: 6px;
|
|
}
|
|
}
|
|
|
|
.pswp__button--arrow--prev {
|
|
left: unset !important;
|
|
right: 0 !important;
|
|
|
|
.pswp__icn {
|
|
left: unset;
|
|
right: 6px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pswp.pswp--behind-header {
|
|
z-index: z("header") - 1;
|
|
}
|
|
|
|
// photoswipe custom caption
|
|
.pswp__caption {
|
|
left: 0;
|
|
bottom: var(--safe-area-inset-bottom);
|
|
width: 100%;
|
|
text-align: center;
|
|
position: absolute;
|
|
|
|
.pswp__caption-title {
|
|
left: 50%;
|
|
bottom: 0;
|
|
color: #fff;
|
|
line-height: 1.25em;
|
|
position: relative;
|
|
max-width: 800px;
|
|
padding: 0 1em 0.25em;
|
|
transform: translateX(-50%);
|
|
transition: transform 0.4s ease;
|
|
}
|
|
|
|
.pswp__caption-ai-description {
|
|
left: 50%;
|
|
bottom: 0;
|
|
color: var(--pswp-icon-color);
|
|
line-height: 1.35;
|
|
position: relative;
|
|
max-width: min(800px, calc(100% - 2rem));
|
|
padding: 0 1em 0.75em;
|
|
font-size: var(--font-down-1);
|
|
overflow-wrap: anywhere;
|
|
transform: translateX(-50%);
|
|
transition: transform 0.4s ease;
|
|
}
|
|
|
|
.pswp__caption-details {
|
|
position: relative;
|
|
left: 50%;
|
|
bottom: 0;
|
|
color: #000;
|
|
background: #fff;
|
|
border-radius: 4px;
|
|
max-width: 200px;
|
|
font-size: var(--font-down-1);
|
|
transform: translate(-50%, 100%);
|
|
opacity: 0;
|
|
transition:
|
|
transform 0.4s ease,
|
|
opacity 0.4s ease;
|
|
}
|
|
}
|
|
|
|
.pswp--caption-expanded .pswp__caption-title {
|
|
transform: translate(-50%, -5px);
|
|
}
|
|
|
|
.pswp--caption-expanded .pswp__caption-ai-description {
|
|
transform: translate(-50%, -5px);
|
|
}
|
|
|
|
.pswp--caption-expanded .pswp__caption-details {
|
|
transform: translate(-50%, -5px);
|
|
opacity: 1;
|
|
}
|
|
|
|
.pswp .pswp__top-bar .pswp__button {
|
|
width: 45px;
|
|
|
|
.pswp__icn {
|
|
left: 6px;
|
|
}
|
|
}
|
|
|
|
.pswp__button--original-image svg,
|
|
.pswp__button--image-info svg,
|
|
.pswp__button--quote-image svg {
|
|
padding: 0.32em;
|
|
}
|
|
|
|
.pswp__custom-counter {
|
|
height: 30px;
|
|
margin-top: 15px;
|
|
margin-inline-start: 20px;
|
|
font-size: 14px;
|
|
line-height: 30px;
|
|
color: var(--pswp-icon-color);
|
|
text-shadow: 1px 1px 3px var(--pswp-icon-color-secondary);
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.pswp--one-slide .pswp__custom-counter {
|
|
display: none;
|
|
}
|