Upload app.py
Browse files
app.py
CHANGED
|
@@ -128,142 +128,145 @@ def build_event_sections(
|
|
| 128 |
time_desc: str,
|
| 129 |
season_desc: str,
|
| 130 |
mood: str,
|
|
|
|
|
|
|
|
|
|
| 131 |
) -> Dict[str, str]:
|
| 132 |
-
"""
|
| 133 |
-
|
| 134 |
-
|
|
|
|
|
|
|
| 135 |
|
| 136 |
-
# Extract event details
|
| 137 |
event_name = event.get("name", "Historical scene")
|
| 138 |
-
event_year = event.get("year",
|
| 139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
actors = event.get("actors") or []
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
elif event_year < 500:
|
| 150 |
-
era_marker = "ancient era"
|
| 151 |
-
elif event_year < 1500:
|
| 152 |
-
era_marker = "medieval era"
|
| 153 |
-
elif event_year < 1800:
|
| 154 |
-
era_marker = "early modern era"
|
| 155 |
-
elif event_year < 1900:
|
| 156 |
-
era_marker = "19th century"
|
| 157 |
-
else:
|
| 158 |
-
era_marker = f"{event_year}"
|
| 159 |
-
|
| 160 |
-
# Get location name/region (prioritize location)
|
| 161 |
-
location_desc = ""
|
| 162 |
-
if region_name:
|
| 163 |
-
region_map = {
|
| 164 |
-
"western_europe": "Western Europe",
|
| 165 |
-
"eastern_europe": "Eastern Europe",
|
| 166 |
-
"north_america": "North America",
|
| 167 |
-
"south_america": "South America",
|
| 168 |
-
"east_asia": "East Asia",
|
| 169 |
-
"middle_east": "Middle East",
|
| 170 |
-
"africa": "Africa",
|
| 171 |
-
}
|
| 172 |
-
location_desc = region_map.get(region_name.lower(), region_name.replace("_", " ").title())
|
| 173 |
-
|
| 174 |
-
# Simplify architecture description
|
| 175 |
-
architecture_lower = architecture.lower() if architecture else ""
|
| 176 |
-
if "roman" in architecture_lower:
|
| 177 |
-
arch_short = "Roman architecture"
|
| 178 |
-
elif "gothic" in architecture_lower:
|
| 179 |
-
arch_short = "Gothic architecture"
|
| 180 |
-
elif "medieval" in architecture_lower:
|
| 181 |
-
arch_short = "medieval architecture"
|
| 182 |
-
elif "asia" in region_name.lower() and event_year < 1900:
|
| 183 |
-
arch_short = "traditional Asian architecture"
|
| 184 |
-
else:
|
| 185 |
-
arch_short = architecture or "period architecture"
|
| 186 |
-
|
| 187 |
-
# Extract key action from narrative (concise)
|
| 188 |
-
key_action = ""
|
| 189 |
-
if narrative:
|
| 190 |
-
# Get first short sentence or phrase
|
| 191 |
-
sentences = [s.strip() for s in narrative.split(".") if len(s.strip()) > 10 and len(s.strip()) < 80]
|
| 192 |
-
if sentences:
|
| 193 |
-
key_action = sentences[0]
|
| 194 |
-
# Trim if too long
|
| 195 |
-
if len(key_action) > 60:
|
| 196 |
-
key_action = key_action[:57] + "..."
|
| 197 |
-
|
| 198 |
-
# Build focused scene: [Event] at [Location] in [Year] at [Time]: [Action]
|
| 199 |
-
# Make time prominent - include it in the main sentence
|
| 200 |
-
time_short = time_desc.split(",")[0] if "," in time_desc else time_desc # Get first part of time description
|
| 201 |
-
|
| 202 |
-
if location_desc:
|
| 203 |
-
if key_action:
|
| 204 |
-
scene_sentence = f"{event_name} at {location_desc} in {era_marker} at {time_short}: {key_action}"
|
| 205 |
-
else:
|
| 206 |
-
scene_sentence = f"{event_name} at {location_desc} in {era_marker} at {time_short}"
|
| 207 |
-
else:
|
| 208 |
-
if key_action:
|
| 209 |
-
scene_sentence = f"{event_name} in {era_marker} at {time_short}: {key_action}"
|
| 210 |
-
else:
|
| 211 |
-
scene_sentence = f"{event_name} in {era_marker} at {time_short}"
|
| 212 |
-
|
| 213 |
-
# Essential participants only (concise)
|
| 214 |
-
if actors and len(actors) > 0:
|
| 215 |
-
main_actors = actors[:2] # Limit to 2 most important
|
| 216 |
-
if len(main_actors) == 1:
|
| 217 |
-
participants_sentence = f"{main_actors[0]} present"
|
| 218 |
-
else:
|
| 219 |
-
participants_sentence = f"{main_actors[0]} and {main_actors[1]} present"
|
| 220 |
-
else:
|
| 221 |
-
participants_sentence = ""
|
| 222 |
-
|
| 223 |
-
# Location architecture (concise, time already in main sentence)
|
| 224 |
-
if location_desc and arch_short:
|
| 225 |
-
location_sentence = f"{location_desc} with {arch_short}"
|
| 226 |
-
elif arch_short:
|
| 227 |
-
location_sentence = arch_short
|
| 228 |
else:
|
| 229 |
-
|
| 230 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
return {
|
| 232 |
-
"
|
| 233 |
-
"participants":
|
| 234 |
-
"
|
|
|
|
|
|
|
|
|
|
| 235 |
}
|
| 236 |
|
| 237 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
def assemble_prompt_from_sections(sections: Dict[str, str], quality: str) -> str:
|
| 239 |
-
"""
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
|
| 268 |
|
| 269 |
def build_fallback_prompt(
|
|
@@ -300,7 +303,7 @@ def build_fallback_prompt(
|
|
| 300 |
"Glitch": "digital glitch art style, cyberpunk aesthetic, data corruption effects, historically themed"
|
| 301 |
}
|
| 302 |
quality = quality_map.get(mood, f"{mood} style, historically inspired")
|
| 303 |
-
|
| 304 |
quality = f"{mood} style, historically accurate, photorealistic, 8K"
|
| 305 |
prompt = assemble_prompt_from_sections(sections, quality)
|
| 306 |
hint = (
|
|
@@ -344,14 +347,14 @@ print("π API Token Status:")
|
|
| 344 |
print("="*60)
|
| 345 |
if HF_TOKEN:
|
| 346 |
print(f"β
HF_TOKEN: Found ({len(HF_TOKEN)} chars) - {HF_TOKEN[:10]}...")
|
| 347 |
-
|
| 348 |
print("β HF_TOKEN: Not found!")
|
| 349 |
print(" Set HUGGINGFACE_API_TOKEN or HF_TOKEN environment variable")
|
| 350 |
|
| 351 |
if GEMINI_API_KEY:
|
| 352 |
print(f"β
GEMINI_API_KEY: Found ({len(GEMINI_API_KEY)} chars) - {GEMINI_API_KEY[:10]}...")
|
| 353 |
genai.configure(api_key=GEMINI_API_KEY)
|
| 354 |
-
|
| 355 |
print("β οΈ GEMINI_API_KEY: Not found (prompts will use fallback)")
|
| 356 |
print("="*60 + "\n")
|
| 357 |
|
|
@@ -420,7 +423,7 @@ def generate_historical_prompt(
|
|
| 420 |
|
| 421 |
if events:
|
| 422 |
focus_event = events[0]
|
| 423 |
-
sections = build_event_sections(focus_event, time_desc, season_desc, mood)
|
| 424 |
# Style-appropriate quality tags
|
| 425 |
if mood in ["Cartoon", "Minecraft", "Retro", "Glitch"]:
|
| 426 |
quality_map = {
|
|
@@ -430,7 +433,7 @@ def generate_historical_prompt(
|
|
| 430 |
"Glitch": "digital glitch art style, cyberpunk aesthetic, data corruption effects, historically themed"
|
| 431 |
}
|
| 432 |
quality = quality_map.get(mood, f"{mood} style, historically inspired")
|
| 433 |
-
|
| 434 |
quality = f"{mood} style, historically accurate, photorealistic, 8K"
|
| 435 |
prompt = assemble_prompt_from_sections(sections, quality)
|
| 436 |
|
|
@@ -452,7 +455,7 @@ def generate_historical_prompt(
|
|
| 452 |
year_match = f"π
~{year_delta} years"
|
| 453 |
elif year_delta <= 10:
|
| 454 |
year_match = f"π
~{year_delta} years apart"
|
| 455 |
-
|
| 456 |
year_match = f"β οΈ {year_delta} years apart"
|
| 457 |
|
| 458 |
hint_lines = [
|
|
@@ -555,7 +558,7 @@ def process_coordinates(lat: float, lon: float, year: int, month: int, day: int,
|
|
| 555 |
prompt = custom_prompt.strip()
|
| 556 |
hint = f"π {lat:.4f}, {lon:.4f} | π
{year}-{month:02d}-{day:02d} {hour}:00 (Custom prompt)"
|
| 557 |
status_parts.append("β
Using custom prompt")
|
| 558 |
-
|
| 559 |
status_parts.append("π Searching historical events...")
|
| 560 |
prompt, hint = generate_historical_prompt(lat, lon, year, month, day, hour, mood)
|
| 561 |
status_parts.append("β
Prompt generated")
|
|
@@ -592,9 +595,9 @@ def process_coordinates(lat: float, lon: float, year: int, month: int, day: int,
|
|
| 592 |
year_badge = "π―"
|
| 593 |
elif year_delta <= 5:
|
| 594 |
year_badge = "π
"
|
| 595 |
-
|
| 596 |
year_badge = "β³"
|
| 597 |
-
|
| 598 |
timeline_md += (
|
| 599 |
f"**{event.get('year')}** {year_badge} β {source_icon} {event.get('name')}{qid_link} "
|
| 600 |
f"({event.get('distance_km')}km"
|
|
@@ -611,7 +614,7 @@ def process_coordinates(lat: float, lon: float, year: int, month: int, day: int,
|
|
| 611 |
participants = event.get("actors") or event.get("participants") or []
|
| 612 |
if participants and source == "wikidata":
|
| 613 |
timeline_md += f"_Participants: {', '.join(participants[:4])}_\n\n"
|
| 614 |
-
|
| 615 |
timeline_md += "_No specific events found in database or Wikidata. Scene generated from era-appropriate context._"
|
| 616 |
|
| 617 |
return image, prompt, hint, status, timeline_md
|
|
@@ -1065,9 +1068,9 @@ def create_app():
|
|
| 1065 |
)
|
| 1066 |
|
| 1067 |
gr.Markdown("### πΌοΈ Generated Image")
|
| 1068 |
-
|
| 1069 |
-
label="",
|
| 1070 |
-
|
| 1071 |
height=600,
|
| 1072 |
type="pil"
|
| 1073 |
)
|
|
@@ -1147,7 +1150,7 @@ def create_app():
|
|
| 1147 |
f"π§ Parsed from prompt (confidence {parsed.confidence:.2f}) Β· "
|
| 1148 |
f"{lat_val:.4f}, {lon_val:.4f}, year {year_val}"
|
| 1149 |
)
|
| 1150 |
-
|
| 1151 |
derived_note = "β οΈ Could not confidently parse prompt context; using manual inputs."
|
| 1152 |
|
| 1153 |
image, prompt, hint, status, timeline = process_coordinates(
|
|
|
|
| 128 |
time_desc: str,
|
| 129 |
season_desc: str,
|
| 130 |
mood: str,
|
| 131 |
+
lat: float,
|
| 132 |
+
lon: float,
|
| 133 |
+
year: int,
|
| 134 |
) -> Dict[str, str]:
|
| 135 |
+
"""Build VISUAL-FIRST event description for image generation.
|
| 136 |
+
|
| 137 |
+
Returns concrete visual elements that image models understand.
|
| 138 |
+
Target: 35-50 words for base prompt (style adds 15-20 more).
|
| 139 |
+
"""
|
| 140 |
|
|
|
|
| 141 |
event_name = event.get("name", "Historical scene")
|
| 142 |
+
event_year = event.get("year", year)
|
| 143 |
+
location = get_location_name(event, lat, lon)
|
| 144 |
+
|
| 145 |
+
# VISUAL SUBJECT (what the image shows)
|
| 146 |
+
subject_type = "historical scene"
|
| 147 |
+
if "battle" in event_name.lower() or "war" in event_name.lower():
|
| 148 |
+
subject_type = "battlefield"
|
| 149 |
+
elif "signing" in event_name.lower() or "declaration" in event_name.lower():
|
| 150 |
+
subject_type = "formal ceremony"
|
| 151 |
+
elif "speech" in event_name.lower() or "address" in event_name.lower():
|
| 152 |
+
subject_type = "public gathering"
|
| 153 |
+
elif "fall" in event_name.lower() or "liberation" in event_name.lower():
|
| 154 |
+
subject_type = "crowd scene"
|
| 155 |
+
|
| 156 |
+
# PARTICIPANTS (who's in the image with period clothing)
|
| 157 |
actors = event.get("actors") or []
|
| 158 |
+
participants_desc = ""
|
| 159 |
+
if actors:
|
| 160 |
+
# Add period-specific clothing descriptors
|
| 161 |
+
clothing = get_period_clothing(event_year)
|
| 162 |
+
if len(actors) == 1:
|
| 163 |
+
participants_desc = f"{actors[0]} in {clothing}"
|
| 164 |
+
elif len(actors) == 2:
|
| 165 |
+
participants_desc = f"{actors[0]} and {actors[1]} in {clothing}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
else:
|
| 167 |
+
participants_desc = f"{actors[0]}, {actors[1]}, and others in {clothing}"
|
| 168 |
+
|
| 169 |
+
# ENVIRONMENT (where the scene takes place)
|
| 170 |
+
location_desc = get_environment_description(location, event_name, event_year)
|
| 171 |
+
|
| 172 |
+
# VISUAL ELEMENTS (period artifacts, architecture)
|
| 173 |
+
artifacts = event.get("artifacts") or []
|
| 174 |
+
visual_elements = join_list(artifacts[:3], "and") if artifacts else ""
|
| 175 |
+
|
| 176 |
+
# LIGHTING (time-based atmospheric description)
|
| 177 |
+
lighting = time_desc # Use full description
|
| 178 |
+
|
| 179 |
return {
|
| 180 |
+
"subject": subject_type,
|
| 181 |
+
"participants": participants_desc,
|
| 182 |
+
"location": location_desc,
|
| 183 |
+
"elements": visual_elements,
|
| 184 |
+
"lighting": lighting,
|
| 185 |
+
"event_name": event_name, # Keep for fallback
|
| 186 |
}
|
| 187 |
|
| 188 |
|
| 189 |
+
def get_period_clothing(year: int) -> str:
|
| 190 |
+
"""Get period-appropriate clothing description."""
|
| 191 |
+
if year < 1500:
|
| 192 |
+
return "medieval robes and tunics"
|
| 193 |
+
elif year < 1700:
|
| 194 |
+
return "Renaissance doublets and robes"
|
| 195 |
+
elif year < 1800:
|
| 196 |
+
return "18th century coats and breeches"
|
| 197 |
+
elif year < 1850:
|
| 198 |
+
return "early 19th century military uniforms"
|
| 199 |
+
elif year < 1900:
|
| 200 |
+
return "Victorian formal attire"
|
| 201 |
+
elif year < 1920:
|
| 202 |
+
return "Edwardian formal dress"
|
| 203 |
+
elif year < 1950:
|
| 204 |
+
return "1940s military uniforms"
|
| 205 |
+
elif year < 1980:
|
| 206 |
+
return "mid-century formal wear"
|
| 207 |
+
else:
|
| 208 |
+
return "modern formal attire"
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def get_environment_description(location: str, event_name: str, year: int) -> str:
|
| 212 |
+
"""Get concrete environmental description."""
|
| 213 |
+
if "Β°" in location:
|
| 214 |
+
env_name = ""
|
| 215 |
+
else:
|
| 216 |
+
env_name = location
|
| 217 |
+
|
| 218 |
+
if "battle" in event_name.lower() or "war" in event_name.lower():
|
| 219 |
+
if year < 1900:
|
| 220 |
+
return f"{env_name} countryside with period cannons, military encampments, and smoke from musket fire" if env_name else "muddy battlefield with period cannons, military encampments, and gunpowder smoke"
|
| 221 |
+
else:
|
| 222 |
+
return f"{env_name} terrain with military vehicles, fortifications, and artillery" if env_name else "war-torn terrain with military vehicles, fortifications, and artillery smoke"
|
| 223 |
+
elif "palace" in location.lower() or "hall" in event_name.lower():
|
| 224 |
+
return "grand ornate interior with period chandeliers, decorative architecture, and formal furnishings"
|
| 225 |
+
elif "street" in event_name.lower() or "crowd" in event_name.lower() or "fall" in event_name.lower():
|
| 226 |
+
return f"{env_name} streets with period buildings, gathered crowds, and urban architecture" if env_name else "city streets with period buildings, gathered crowds, and architectural details"
|
| 227 |
+
else:
|
| 228 |
+
return f"{env_name} with historically accurate period architecture and setting" if env_name else "period-accurate setting with appropriate historical architecture"
|
| 229 |
+
|
| 230 |
+
|
| 231 |
def assemble_prompt_from_sections(sections: Dict[str, str], quality: str) -> str:
|
| 232 |
+
"""Assemble VISUAL-FIRST prompt for image generation.
|
| 233 |
+
|
| 234 |
+
Format: "[Subject] showing [participants]. [Environment with elements]. [Lighting]."
|
| 235 |
+
NO metadata - only visual descriptions that models understand.
|
| 236 |
+
"""
|
| 237 |
+
|
| 238 |
+
subject = sections.get("subject", "historical scene")
|
| 239 |
+
participants = sections.get("participants", "")
|
| 240 |
+
location = sections.get("location", "")
|
| 241 |
+
elements = sections.get("elements", "")
|
| 242 |
+
lighting = sections.get("lighting", "")
|
| 243 |
+
|
| 244 |
+
# Build prompt sentence by sentence
|
| 245 |
+
parts = []
|
| 246 |
+
|
| 247 |
+
# Sentence 1: Subject + Participants
|
| 248 |
+
if participants:
|
| 249 |
+
parts.append(f"{subject.capitalize()} showing {participants}")
|
| 250 |
+
else:
|
| 251 |
+
event_name = sections.get("event_name", "historical event")
|
| 252 |
+
parts.append(f"{subject.capitalize()} depicting {event_name}")
|
| 253 |
+
|
| 254 |
+
# Sentence 2: Environment WITH Elements (combined)
|
| 255 |
+
if location and elements:
|
| 256 |
+
parts.append(f"{location} with {elements}")
|
| 257 |
+
elif location:
|
| 258 |
+
parts.append(location)
|
| 259 |
+
elif elements:
|
| 260 |
+
parts.append(f"Scene with {elements}")
|
| 261 |
+
|
| 262 |
+
# Sentence 3: Lighting/Atmosphere
|
| 263 |
+
if lighting:
|
| 264 |
+
parts.append(f"{lighting}")
|
| 265 |
+
|
| 266 |
+
# Join all parts with periods for clear structure
|
| 267 |
+
final = ". ".join(parts)
|
| 268 |
+
|
| 269 |
+
return final.strip()
|
| 270 |
|
| 271 |
|
| 272 |
def build_fallback_prompt(
|
|
|
|
| 303 |
"Glitch": "digital glitch art style, cyberpunk aesthetic, data corruption effects, historically themed"
|
| 304 |
}
|
| 305 |
quality = quality_map.get(mood, f"{mood} style, historically inspired")
|
| 306 |
+
else:
|
| 307 |
quality = f"{mood} style, historically accurate, photorealistic, 8K"
|
| 308 |
prompt = assemble_prompt_from_sections(sections, quality)
|
| 309 |
hint = (
|
|
|
|
| 347 |
print("="*60)
|
| 348 |
if HF_TOKEN:
|
| 349 |
print(f"β
HF_TOKEN: Found ({len(HF_TOKEN)} chars) - {HF_TOKEN[:10]}...")
|
| 350 |
+
else:
|
| 351 |
print("β HF_TOKEN: Not found!")
|
| 352 |
print(" Set HUGGINGFACE_API_TOKEN or HF_TOKEN environment variable")
|
| 353 |
|
| 354 |
if GEMINI_API_KEY:
|
| 355 |
print(f"β
GEMINI_API_KEY: Found ({len(GEMINI_API_KEY)} chars) - {GEMINI_API_KEY[:10]}...")
|
| 356 |
genai.configure(api_key=GEMINI_API_KEY)
|
| 357 |
+
else:
|
| 358 |
print("β οΈ GEMINI_API_KEY: Not found (prompts will use fallback)")
|
| 359 |
print("="*60 + "\n")
|
| 360 |
|
|
|
|
| 423 |
|
| 424 |
if events:
|
| 425 |
focus_event = events[0]
|
| 426 |
+
sections = build_event_sections(focus_event, time_desc, season_desc, mood, lat, lon, year)
|
| 427 |
# Style-appropriate quality tags
|
| 428 |
if mood in ["Cartoon", "Minecraft", "Retro", "Glitch"]:
|
| 429 |
quality_map = {
|
|
|
|
| 433 |
"Glitch": "digital glitch art style, cyberpunk aesthetic, data corruption effects, historically themed"
|
| 434 |
}
|
| 435 |
quality = quality_map.get(mood, f"{mood} style, historically inspired")
|
| 436 |
+
else:
|
| 437 |
quality = f"{mood} style, historically accurate, photorealistic, 8K"
|
| 438 |
prompt = assemble_prompt_from_sections(sections, quality)
|
| 439 |
|
|
|
|
| 455 |
year_match = f"π
~{year_delta} years"
|
| 456 |
elif year_delta <= 10:
|
| 457 |
year_match = f"π
~{year_delta} years apart"
|
| 458 |
+
else:
|
| 459 |
year_match = f"β οΈ {year_delta} years apart"
|
| 460 |
|
| 461 |
hint_lines = [
|
|
|
|
| 558 |
prompt = custom_prompt.strip()
|
| 559 |
hint = f"π {lat:.4f}, {lon:.4f} | π
{year}-{month:02d}-{day:02d} {hour}:00 (Custom prompt)"
|
| 560 |
status_parts.append("β
Using custom prompt")
|
| 561 |
+
else:
|
| 562 |
status_parts.append("π Searching historical events...")
|
| 563 |
prompt, hint = generate_historical_prompt(lat, lon, year, month, day, hour, mood)
|
| 564 |
status_parts.append("β
Prompt generated")
|
|
|
|
| 595 |
year_badge = "π―"
|
| 596 |
elif year_delta <= 5:
|
| 597 |
year_badge = "π
"
|
| 598 |
+
else:
|
| 599 |
year_badge = "β³"
|
| 600 |
+
|
| 601 |
timeline_md += (
|
| 602 |
f"**{event.get('year')}** {year_badge} β {source_icon} {event.get('name')}{qid_link} "
|
| 603 |
f"({event.get('distance_km')}km"
|
|
|
|
| 614 |
participants = event.get("actors") or event.get("participants") or []
|
| 615 |
if participants and source == "wikidata":
|
| 616 |
timeline_md += f"_Participants: {', '.join(participants[:4])}_\n\n"
|
| 617 |
+
else:
|
| 618 |
timeline_md += "_No specific events found in database or Wikidata. Scene generated from era-appropriate context._"
|
| 619 |
|
| 620 |
return image, prompt, hint, status, timeline_md
|
|
|
|
| 1068 |
)
|
| 1069 |
|
| 1070 |
gr.Markdown("### πΌοΈ Generated Image")
|
| 1071 |
+
image_output = gr.Image(
|
| 1072 |
+
label="",
|
| 1073 |
+
show_label=False,
|
| 1074 |
height=600,
|
| 1075 |
type="pil"
|
| 1076 |
)
|
|
|
|
| 1150 |
f"π§ Parsed from prompt (confidence {parsed.confidence:.2f}) Β· "
|
| 1151 |
f"{lat_val:.4f}, {lon_val:.4f}, year {year_val}"
|
| 1152 |
)
|
| 1153 |
+
else:
|
| 1154 |
derived_note = "β οΈ Could not confidently parse prompt context; using manual inputs."
|
| 1155 |
|
| 1156 |
image, prompt, hint, status, timeline = process_coordinates(
|