Follow Picture Agent gallery data URL

This commit is contained in:
boos
2026-06-02 17:30:15 +08:00
parent 938597b766
commit 55bd3f41f8
+68 -7
View File
@@ -14,12 +14,15 @@ use axum::{
routing::{get, post}, routing::{get, post},
}; };
use reqwest::Client; use reqwest::Client;
use reqwest::Url;
use serde::Deserialize; use serde::Deserialize;
use serde_json::{Value, json}; use serde_json::{Value, json};
use std::time::Duration; use std::time::Duration;
const TEMPLATE_GALLERY_URL: &str = const TEMPLATE_GALLERY_PAGE_URL: &str =
"https://weiyyin.github.io/linux-do-gpt-image/linux_do_2036927_prompts_images.filtered.json"; "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 TASK_TYPE_PICTURE_GENERATION: &str = "picture-agent-generation";
const TEMPLATE_GALLERY_TIMEOUT_SECS: u64 = 30; const TEMPLATE_GALLERY_TIMEOUT_SECS: u64 = 30;
const PICTURE_GENERATION_TIMEOUT_SECS: u64 = 300; 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("deepseek-chat"));
assert!(!is_picture_model_pattern("qwen-plus")); 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 { fn prompt_title(prompt: &str, post_number: Option<i64>) -> String {
@@ -364,7 +384,7 @@ async fn templates_handler(
Ok(Json(json!({ Ok(Json(json!({
"success": true, "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), "fallback": remote_status.get("ok").and_then(Value::as_bool) != Some(true),
"remote": remote_status, "remote": remote_status,
"templates": templates, "templates": templates,
@@ -378,13 +398,15 @@ async fn fetch_remote_gallery_templates(
if limit == 0 { if limit == 0 {
return Ok(Vec::new()); return Ok(Vec::new());
} }
let items = crate::template_http::client(config, TEMPLATE_GALLERY_TIMEOUT_SECS) let client = crate::template_http::client(config, TEMPLATE_GALLERY_TIMEOUT_SECS);
.get(TEMPLATE_GALLERY_URL) let data_url = resolve_gallery_data_url(&client).await?;
let items = client
.get(&data_url)
.send() .send()
.await .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() .error_for_status()
.map_err(|err| format!("template gallery returned {err}"))? .map_err(|err| format!("template gallery data returned {err}"))?
.json::<Vec<GalleryItem>>() .json::<Vec<GalleryItem>>()
.await .await
.map_err(|err| format!("failed to parse templates: {err}"))?; .map_err(|err| format!("failed to parse templates: {err}"))?;
@@ -427,6 +449,45 @@ async fn fetch_remote_gallery_templates(
.collect()) .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> { fn builtin_picture_templates(limit: usize) -> Vec<Value> {
[ [
( (