unknown
Improved UI
438ebc5
Raw
History Blame Contribute Delete
12.8 kB
import json
import requests
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from django.utils.decorators import method_decorator
from django.views import View
from .models import LocationData, ConstellationQuery
from google import genai as google_genai
from datetime import datetime
import math
import re
from dotenv import load_dotenv
load_dotenv()
import os
class ConstellationFinderView(View):
def get(self, request):
return render(request, 'Locator/index.html')
@csrf_exempt
def save_location(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
lat = data.get('latitude')
lng = data.get('longitude')
accuracy = data.get('accuracy', 0)
if not lat or not lng:
return JsonResponse({
'status': 'error',
'message': 'Latitude and longitude are required'
})
location = LocationData.objects.create(
user=request.user if request.user.is_authenticated else None,
latitude=lat,
longitude=lng,
accuracy=accuracy
)
return JsonResponse({
'status': 'success',
'location_id': location.id,
'message': 'Location saved successfully'
})
except json.JSONDecodeError:
return JsonResponse({
'status': 'error',
'message': 'Invalid JSON data'
})
except Exception as e:
return JsonResponse({
'status': 'error',
'message': f'Error saving location: {str(e)}'
})
return JsonResponse({'status': 'error', 'message': 'Invalid request method'})
@csrf_exempt
def find_constellations(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
location_id = data.get('location_id')
if not location_id:
return JsonResponse({
'status': 'error',
'message': 'Location ID is required'
})
# Get location from database
try:
location = LocationData.objects.get(id=location_id)
except LocationData.DoesNotExist:
return JsonResponse({
'status': 'error',
'message': 'Location not found'
})
# Configure Gemini AI
gemini_api_key = os.getenv('GEMINI_API_KEY')
if not gemini_api_key:
return JsonResponse({
'status': 'error',
'message': 'Sky mapping service is not configured'
})
gemini_client = google_genai.Client(api_key=gemini_api_key)
current_time = datetime.now()
current_hour = current_time.hour
prompt = f"""
Location: Latitude {location.latitude}, Longitude {location.longitude}
Date: {current_time.strftime('%Y-%m-%d')}
Time: {current_time.strftime('%H:%M')} ({current_hour}:00)
Please provide a simple response about constellations visible from this location tonight:
1. Give a brief description (2-3 sentences) of what constellations are visible
2. List 5-7 major constellations that can be seen
3. For each constellation, specify the general compass direction (North, South, East, West, Northeast, Northwest, Southeast, Southwest, or Overhead)
Also tell where am i based on location.
Keep the response simple and practical for someone using a phone compass to find constellations.
Format: Just plain text, no special formatting or symbols.
"""
# Get response from Gemini
try:
response = gemini_client.models.generate_content(
model='gemini-3.5-flash',
contents=prompt
)
gemini_response = response.text.strip()
# Extract constellation information
visible_constellations = extract_constellation_names(gemini_response)
compass_directions = extract_compass_directions(gemini_response, visible_constellations)
# Save query to database
constellation_query = ConstellationQuery.objects.create(
location=location,
query_text=prompt,
gemini_response=gemini_response,
visible_constellations=visible_constellations
)
return JsonResponse({
'status': 'success',
'response': gemini_response,
'visible_constellations': visible_constellations,
'compass_directions': compass_directions,
'query_id': constellation_query.id
})
except Exception as e:
return JsonResponse({
'status': 'error',
'message': 'Unable to map the sky right now. Please try again in a moment.'
})
except json.JSONDecodeError:
return JsonResponse({
'status': 'error',
'message': 'Invalid JSON data'
})
except Exception as e:
return JsonResponse({
'status': 'error',
'message': f'Server error: {str(e)}'
})
return JsonResponse({'status': 'error', 'message': 'Invalid request method'})
def extract_constellation_names(text):
"""Extract constellation names from Gemini response using improved pattern matching"""
# Common constellation names to look for
common_constellations = [
'Ursa Major', 'Big Dipper', 'Great Bear',
'Ursa Minor', 'Little Dipper', 'Little Bear',
'Cassiopeia', 'The Queen',
'Orion', 'The Hunter',
'Leo', 'The Lion',
'Virgo', 'The Maiden',
'Libra', 'The Scales',
'Scorpius', 'Scorpio', 'The Scorpion',
'Sagittarius', 'The Archer',
'Capricornus', 'Capricorn', 'The Sea Goat',
'Aquarius', 'The Water Bearer',
'Pisces', 'The Fish',
'Aries', 'The Ram',
'Taurus', 'The Bull',
'Gemini', 'The Twins',
'Cancer', 'The Crab',
'Andromeda', 'The Princess',
'Perseus', 'The Hero',
'Auriga', 'The Charioteer',
'Bootes', 'Boötes', 'The Herdsman',
'Corona Borealis', 'Northern Crown',
'Cygnus', 'The Swan',
'Lyra', 'The Harp',
'Aquila', 'The Eagle',
'Draco', 'The Dragon',
'Hercules', 'The Strongman',
'Ophiuchus', 'The Serpent Bearer',
'Serpens', 'The Serpent',
'Canis Major', 'The Great Dog',
'Canis Minor', 'The Little Dog',
'Pegasus', 'The Winged Horse',
'Cepheus', 'The King',
'Lacerta', 'The Lizard',
'Vela', 'The Sails',
'Centaurus', 'The Centaur',
'Crux', 'Southern Cross',
'Polaris', 'North Star', 'Pole Star'
]
found_constellations = []
text_upper = text.upper()
for constellation in common_constellations:
# Check if constellation name appears in text
if constellation.upper() in text_upper:
# Use the most common name
if constellation in ['Big Dipper', 'Great Bear']:
if 'Ursa Major' not in found_constellations:
found_constellations.append('Ursa Major')
elif constellation in ['Little Dipper', 'Little Bear']:
if 'Ursa Minor' not in found_constellations:
found_constellations.append('Ursa Minor')
elif constellation in ['The Queen']:
if 'Cassiopeia' not in found_constellations:
found_constellations.append('Cassiopeia')
elif constellation in ['The Hunter']:
if 'Orion' not in found_constellations:
found_constellations.append('Orion')
elif constellation in ['Scorpio', 'The Scorpion']:
if 'Scorpius' not in found_constellations:
found_constellations.append('Scorpius')
elif constellation in ['Capricorn', 'The Sea Goat']:
if 'Capricornus' not in found_constellations:
found_constellations.append('Capricornus')
elif constellation in ['Boötes', 'The Herdsman']:
if 'Bootes' not in found_constellations:
found_constellations.append('Bootes')
elif constellation in ['North Star', 'Pole Star']:
if 'Polaris' not in found_constellations:
found_constellations.append('Polaris')
elif constellation in ['Southern Cross']:
if 'Crux' not in found_constellations:
found_constellations.append('Crux')
else:
# Use the constellation name as-is if it's not an alias
clean_name = constellation.replace('The ', '')
if clean_name not in found_constellations:
found_constellations.append(clean_name)
# Remove duplicates while preserving order
unique_constellations = []
for constellation in found_constellations:
if constellation not in unique_constellations:
unique_constellations.append(constellation)
return unique_constellations[:8] # Limit to 8 constellations
def extract_compass_directions(text, constellations):
"""Extract compass directions for each constellation from Gemini response"""
directions = {}
# Direction keywords mapping
direction_keywords = {
'north': ['North', 'N'],
'northeast': ['Northeast', 'NE'],
'east': ['East', 'E'],
'southeast': ['Southeast', 'SE'],
'south': ['South', 'S'],
'southwest': ['Southwest', 'SW'],
'west': ['West', 'W'],
'northwest': ['Northwest', 'NW'],
'overhead': ['Overhead', 'Zenith', 'Above']
}
# Default directions for common constellations (backup)
default_directions = {
'Ursa Major': 'North',
'Ursa Minor': 'North',
'Cassiopeia': 'North',
'Polaris': 'North',
'Orion': 'South',
'Leo': 'South',
'Scorpius': 'South',
'Sagittarius': 'South',
'Cygnus': 'Overhead',
'Lyra': 'West',
'Aquila': 'East',
'Andromeda': 'Northeast',
'Perseus': 'Northeast',
'Pegasus': 'West',
'Taurus': 'West',
'Gemini': 'East'
}
# Try to extract directions from text
for constellation in constellations:
found_direction = None
# Look for constellation name followed by direction
for direction_key, direction_names in direction_keywords.items():
for direction_name in direction_names:
# Pattern: constellation name followed by direction within reasonable distance
pattern = rf'{re.escape(constellation)}.*?{re.escape(direction_name.lower())}'
if re.search(pattern, text.lower(), re.IGNORECASE):
found_direction = direction_names[0] # Use first (full) name
break
# Pattern: direction followed by constellation name
pattern = rf'{re.escape(direction_name.lower())}.*?{re.escape(constellation)}'
if re.search(pattern, text.lower(), re.IGNORECASE):
found_direction = direction_names[0]
break
if found_direction:
break
# Use found direction or fall back to default
if found_direction:
directions[constellation] = found_direction
elif constellation in default_directions:
directions[constellation] = default_directions[constellation]
else:
# Random fallback direction
import random
directions[constellation] = random.choice(['North', 'South', 'East', 'West', 'Northeast', 'Northwest', 'Southeast', 'Southwest'])
return directions