feat(wikidata): enhance property value parsing and improve time handling
- Refactor `fetch_item_properties` to handle nested JSON types efficiently - Introduce `parse_property_value` for structured processing of various value types - Handle time values with varying precision (year, month, day) - Parse and format dates from RFC 3339 format - Support fetching and displaying labels for Wikidata entity references - Replace raw JSON object handling with cleaner structured parsing - Update property label fetching and signal updates for better UI data synchronization
This commit is contained in:
parent
a40e9c98c4
commit
af921088f9
3 changed files with 145 additions and 9 deletions
77
Cargo.lock
generated
77
Cargo.lock
generated
|
@ -287,6 +287,21 @@ version = "0.2.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.94"
|
||||
|
@ -687,6 +702,20 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.2"
|
||||
|
@ -737,6 +766,7 @@ version = "0.1.3"
|
|||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-web",
|
||||
"chrono",
|
||||
"console_error_panic_hook",
|
||||
"futures",
|
||||
"gloo-net 0.5.0",
|
||||
|
@ -831,6 +861,12 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.16"
|
||||
|
@ -1383,6 +1419,29 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
|
@ -2124,6 +2183,15 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
|
@ -3507,6 +3575,15 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
|
|
@ -31,6 +31,7 @@ serde_json="1.0.133"
|
|||
thiserror = "2.0.9"
|
||||
zerofrom = "0.1"
|
||||
mio = "0.8"
|
||||
chrono = "0.4"
|
||||
|
||||
[features]
|
||||
default = ["ssr"]
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::models::item::Item;
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::JsCast;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
struct WikidataSuggestion {
|
||||
|
@ -299,10 +300,68 @@ pub fn ItemsList(
|
|||
});
|
||||
};
|
||||
|
||||
// function to handle different nested JSON types for property values
|
||||
async fn parse_property_value(value: &serde_json::Value) -> String {
|
||||
match value {
|
||||
serde_json::Value::String(text) => text.clone(),
|
||||
serde_json::Value::Number(num) => num.to_string(),
|
||||
serde_json::Value::Object(map) => {
|
||||
|
||||
// Handle time values
|
||||
if let Some(time_value) = map.get("time") {
|
||||
let precision = map.get("precision").and_then(|p| p.as_u64()).unwrap_or(11);
|
||||
|
||||
if let Some(time_str) = time_value.as_str() {
|
||||
if let Ok(parsed_date) = chrono::DateTime::parse_from_rfc3339(time_str.trim_start_matches('+')) {
|
||||
return match precision {
|
||||
9 => parsed_date.format("%Y").to_string(), // Year precision
|
||||
10 => parsed_date.format("%Y-%m").to_string(), // Month precision
|
||||
11 => parsed_date.format("%Y-%m-%d").to_string(), // Day precision
|
||||
_ => parsed_date.format("%Y-%m-%d %H:%M:%S").to_string(),
|
||||
};
|
||||
}
|
||||
}
|
||||
return "Invalid time format".to_string();
|
||||
}
|
||||
|
||||
// Handle Wikidata entity references
|
||||
if let Some(id) = map.get("id") {
|
||||
// Handle Wikidata entity references
|
||||
let entity_id = id.as_str().unwrap_or("");
|
||||
if entity_id.starts_with("Q") {
|
||||
return fetch_entity_label(entity_id).await;
|
||||
}
|
||||
}
|
||||
serde_json::to_string(map).unwrap_or("Complex Object".to_string())
|
||||
}
|
||||
_ => "Unsupported data type".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_entity_label(entity_id: &str) -> String {
|
||||
let url = format!(
|
||||
"https://www.wikidata.org/w/api.php?action=wbgetentities&ids={}&props=labels&languages=en&format=json&origin=*",
|
||||
entity_id
|
||||
);
|
||||
|
||||
match gloo_net::http::Request::get(&url).send().await {
|
||||
Ok(response) => {
|
||||
if let Ok(data) = response.json::<serde_json::Value>().await {
|
||||
if let Some(entity) = data["entities"][entity_id]["labels"]["en"]["value"].as_str() {
|
||||
return entity.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => log!("Error fetching entity label: {:?}", err),
|
||||
}
|
||||
|
||||
entity_id.to_string() // Fallback to entity ID if label fetch fails
|
||||
}
|
||||
|
||||
//function to fetch properties
|
||||
async fn fetch_item_properties(wikidata_id: &str, set_fetched_properties: WriteSignal<HashMap<String, String>>, set_property_labels: WriteSignal<HashMap<String, String>>,) -> HashMap<String, String> {
|
||||
let url = format!(
|
||||
"https://www.wikidata.org/wiki/Special:EntityData/{}.json",
|
||||
"https://www.wikidata.org/w/api.php?action=wbgetentities&ids={}&format=json&props=claims&origin=*",
|
||||
wikidata_id
|
||||
);
|
||||
|
||||
|
@ -313,17 +372,16 @@ pub fn ItemsList(
|
|||
if let Some(entity) = entities.get(wikidata_id) {
|
||||
if let Some(claims) = entity["claims"].as_object() {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
for (property, values) in claims {
|
||||
if let Some(value) = values[0]["mainsnak"]["datavalue"]["value"].as_str() {
|
||||
result.insert(property.clone(), value.to_string());
|
||||
} else if let Some(value) = values[0]["mainsnak"]["datavalue"]["value"].as_object() {
|
||||
result.insert(property.clone(), serde_json::to_string(value).unwrap());
|
||||
} else if let Some(value) = values[0]["mainsnak"]["datavalue"]["value"].as_f64() {
|
||||
result.insert(property.clone(), value.to_string());
|
||||
} else {
|
||||
result.insert(property.clone(), "Unsupported data type".to_string());
|
||||
for value_entry in values.as_array().unwrap_or(&vec![]) {
|
||||
if let Some(datavalue) = value_entry["mainsnak"]["datavalue"].get("value") {
|
||||
let parsed_value = parse_property_value(datavalue).await;
|
||||
result.insert(property.clone(), parsed_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch labels for the properties
|
||||
let property_ids = result.keys().cloned().collect::<Vec<_>>();
|
||||
let labels = fetch_property_labels(property_ids).await;
|
||||
|
|
Loading…
Add table
Reference in a new issue