Follow Picture Agent gallery data URL

This commit is contained in:
boos
2026-06-02 17:30:15 +08:00
parent deb8edded2
commit eddf6b36b5
+68 -7
View File
@@ -14,12 +14,15 @@ use axum::{
routing::{get, post},
};
use reqwest::Client;
use reqwest::Url;
use serde::Deserialize;
use serde_json::{Value, json};
use std::time::Duration;
const TEMPLATE_GALLERY_URL: &str =
"https://weiyyin.github.io/linux-do-gpt-image/linux_do_2036927_prompts_images.filtered.json";
const TEMPLATE_GALLERY_PAGE_URL: &str =
"https://weiyyin.github.io/linux-do-gpt-image/prompt_gallery.html";
const TEMPLATE_GALLERY_FALLBACK_DATA_URL: &str =
"https://weiyyin.github.io/linux-do-gpt-image/linux_do_2036927_prompts_images.with_tags.json";
const TASK_TYPE_PICTURE_GENERATION: &str = "picture-agent-generation";
const TEMPLATE_GALLERY_TIMEOUT_SECS: u64 = 30;
const PICTURE_GENERATION_TIMEOUT_SECS: u64 = 300;
@@ -285,6 +288,23 @@ mod tests {
assert!(!is_picture_model_pattern("deepseek-chat"));
assert!(!is_picture_model_pattern("qwen-plus"));
}
#[test]
fn extracts_gallery_data_url_from_page_script() {
let html = r#"
<script>
const DATA_URL = "./linux_do_2036927_prompts_images.with_tags.json";
</script>
"#;
assert_eq!(
extract_gallery_data_url(html).as_deref(),
Some("./linux_do_2036927_prompts_images.with_tags.json")
);
assert_eq!(
absolute_gallery_url("./linux_do_2036927_prompts_images.with_tags.json").unwrap(),
"https://weiyyin.github.io/linux-do-gpt-image/linux_do_2036927_prompts_images.with_tags.json"
);
}
}
fn prompt_title(prompt: &str, post_number: Option<i64>) -> String {
@@ -364,7 +384,7 @@ async fn templates_handler(
Ok(Json(json!({
"success": true,
"sourceUrl": "https://weiyyin.github.io/linux-do-gpt-image/prompt_gallery.html",
"sourceUrl": TEMPLATE_GALLERY_PAGE_URL,
"fallback": remote_status.get("ok").and_then(Value::as_bool) != Some(true),
"remote": remote_status,
"templates": templates,
@@ -378,13 +398,15 @@ async fn fetch_remote_gallery_templates(
if limit == 0 {
return Ok(Vec::new());
}
let items = crate::template_http::client(config, TEMPLATE_GALLERY_TIMEOUT_SECS)
.get(TEMPLATE_GALLERY_URL)
let client = crate::template_http::client(config, TEMPLATE_GALLERY_TIMEOUT_SECS);
let data_url = resolve_gallery_data_url(&client).await?;
let items = client
.get(&data_url)
.send()
.await
.map_err(|err| format!("failed to fetch templates: {err}"))?
.map_err(|err| format!("failed to fetch templates from {data_url}: {err}"))?
.error_for_status()
.map_err(|err| format!("template gallery returned {err}"))?
.map_err(|err| format!("template gallery data returned {err}"))?
.json::<Vec<GalleryItem>>()
.await
.map_err(|err| format!("failed to parse templates: {err}"))?;
@@ -427,6 +449,45 @@ async fn fetch_remote_gallery_templates(
.collect())
}
async fn resolve_gallery_data_url(client: &Client) -> Result<String, String> {
let html = client
.get(TEMPLATE_GALLERY_PAGE_URL)
.send()
.await
.map_err(|err| format!("failed to fetch template gallery page: {err}"))?
.error_for_status()
.map_err(|err| format!("template gallery page returned {err}"))?
.text()
.await
.map_err(|err| format!("failed to read template gallery page: {err}"))?;
let data_url = extract_gallery_data_url(&html)
.ok_or_else(|| "template gallery page did not expose DATA_URL".to_string())?;
absolute_gallery_url(&data_url)
}
fn extract_gallery_data_url(html: &str) -> Option<String> {
let regex = regex::Regex::new(r#"(?m)\bDATA_URL\s*=\s*["']([^"']+)["']"#).ok()?;
regex
.captures(html)
.and_then(|captures| captures.get(1))
.map(|match_| match_.as_str().trim().to_string())
.filter(|value| !value.is_empty())
}
fn absolute_gallery_url(value: &str) -> Result<String, String> {
if value.starts_with("http://") || value.starts_with("https://") {
return Ok(value.to_string());
}
let base = Url::parse(TEMPLATE_GALLERY_PAGE_URL)
.map_err(|err| format!("invalid template gallery page URL: {err}"))?;
base.join(value)
.map(|url| url.to_string())
.or_else(|_| Url::parse(TEMPLATE_GALLERY_FALLBACK_DATA_URL).map(|url| url.to_string()))
.map_err(|err| format!("invalid template gallery data URL: {err}"))
}
fn builtin_picture_templates(limit: usize) -> Vec<Value> {
[
(