Spaces:
Sleeping
Sleeping
we need to add langchain control to HF AI agent code provided below. | |
State should have location_provided boolean, plant str, root_crop boolean and location_cautions str, answer str | |
To the existing workflow we need to add next steps: | |
1. check if plant name is provided and recodnized (for root crop or above ground) | |
update plant, root_crop | |
2. identify if location is provided in the request, | |
and if so, set location_provided true, identify if location is not on Earth, | |
and if so, | |
update location_cautions with "Salute you explorer!" + explain why moon indices don't work outside of Earth, and suggest principles analogous indices could be developed on other planets. | |
final_answer = location_cautions | |
otherwise, check if location is not fertile or sutable for planting outdoor | |
and if so, update location_cautions so user should ensure required conditions for the plant (e.g. indoor) before relying on the fertility indices. | |
otherwise, proceed with request to #2 | |
otherwise, proceed with request to #2 | |
3. check if request about planting or pruning? | |
and for planting | |
check if plant not defined, | |
and if so, clarify from user plant and if not recognized clarify if it is crop root | |
update plant variable, | |
find out corresponding fertility index to answer | |
for pruning find out pruning index | |
4. if location_caution <> 0 then answer = answer + location_caution | |
AI agent code: | |
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool | |
import smolagents # Added for aliasing | |
# from smolagents.security import E2BSandbox | |
import datetime | |
import pytz | |
import yaml | |
from skyfield.api import load, Topos, load_file | |
from skyfield import almanac | |
from tools.final_answer import FinalAnswerTool | |
from Gradio_UI import GradioUI | |
import os | |
import base64 | |
# Add the alias before instrumentation | |
smolagents.ApiModel = smolagents.HfApiModel | |
LANGFUSE_PUBLIC_KEY="pk-lf-133099c7-8644-49e8-8f6e-ec8bd6d543fd" | |
LF_SECRET_KEY = os.environ["LANGFUSE_SECRET_KEY"] | |
LANGFUSE_AUTH=base64.b64encode(f"{LANGFUSE_PUBLIC_KEY}:{LF_SECRET_KEY}".encode()).decode() | |
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://cloud.langfuse.com/api/public/otel" # EU data region | |
# os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://us.cloud.langfuse.com/api/public/otel" # US data region | |
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}" | |
from opentelemetry.sdk.trace import TracerProvider | |
from openinference.instrumentation.smolagents import SmolagentsInstrumentor | |
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter | |
from opentelemetry.sdk.trace.export import SimpleSpanProcessor | |
trace_provider = TracerProvider() | |
trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter())) | |
SmolagentsInstrumentor().instrument(tracer_provider=trace_provider) | |
# Load ephemeris and timescale | |
planets = load('https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/de440.bsp') | |
ts = load.timescale() | |
# Define Zodiac signs and their boundaries (0° to 360° ecliptic longitude) | |
ZODIAC_SIGNS = [ | |
("Aries", 0, 30), | |
("Taurus", 30, 60), | |
("Gemini", 60, 90), | |
("Cancer", 90, 120), | |
("Leo", 120, 150), | |
("Virgo", 150, 180), | |
("Libra", 180, 210), | |
("Scorpio", 210, 240), | |
("Sagittarius", 240, 270), | |
("Capricorn", 270, 300), | |
("Aquarius", 300, 330), | |
("Pisces", 330, 360), | |
] | |
# Moon phase boundaries (0° to 360° phase angle) for display purposes | |
MOON_PHASES = [ | |
("New Moon", 0, 45), | |
("Waxing Crescent", 45, 90), | |
("First Quarter", 90, 135), | |
("Waxing Gibbous", 135, 180), | |
("Full Moon", 180, 225), | |
("Waning Gibbous", 225, 270), | |
("Last Quarter", 270, 315), | |
("Waning Crescent", 315, 360), | |
] | |
# Fertility sign coefficients (applicable to all plants) | |
FERTILITY_SIGN_COEFFS = { | |
"Aries": 1, | |
"Taurus": 2, | |
"Gemini": 0, | |
"Cancer": 2, | |
"Leo": 1, | |
"Virgo": 0, | |
"Libra": 0.5, | |
"Scorpio": 1.5, | |
"Sagittarius": 1, | |
"Capricorn": 1, | |
"Aquarius": 0, | |
"Pisces": 2, | |
} | |
# Pruning sign coefficients (applicable to all plants) | |
PRUNING_SIGN_COEFFS = { | |
"Aries": 1, | |
"Taurus": 0, | |
"Gemini": 2, | |
"Cancer": 0, | |
"Leo": 1, | |
"Virgo": 2, | |
"Libra": 1.5, | |
"Scorpio": 0.5, | |
"Sagittarius": 1, | |
"Capricorn": 1, | |
"Aquarius": 2, | |
"Pisces": 0, | |
} | |
# Fertility phase coefficients for above-ground plants | |
FERTILITY_PHASE_COEFFS_ABOVE = { | |
"New Moon": 0, | |
"Waxing Moon": 1, | |
"Full Moon": 0, | |
"Waning Moon": 0.5, | |
} | |
# Fertility phase coefficients for root crops | |
FERTILITY_PHASE_COEFFS_ROOT = { | |
"New Moon": 0, | |
"Waxing Moon": 0.5, | |
"Full Moon": 0, | |
"Waning Moon": 1, | |
} | |
# Pruning phase coefficients | |
PRUNING_PHASE_COEFFS = { | |
"New Moon": 0, | |
"Waxing Moon": 1, | |
"Full Moon": 0, | |
"Waning Moon": 0.5, | |
} | |
@tool | |
def get_moon_info(date_time: str) -> dict: | |
""" | |
Returns Moon's Zodiac position, phase, and fertility and pruning indices for the given date/time. | |
The fertility and pruning indices are calculated as sum of sign and phase fertility values of the Moon position. Moon sign fertility | |
amounts up to 2.0 value and phase fertility value could be 1.0 max. | |
It is observed that when Moon is in different Zodiac signs, the fertility of new plants and impact of pruning differs. | |
When Moon is in fertile sign the plant is in the active phase, when all processes are particularly intense, and any intervention | |
such as pruning can be very traumatic for the plant. Here: | |
Most fertile signs: Taurus, Pisces, Cancer - Plants are in the active growth phase, juices and nutrients actively circulate | |
in the plant, and it is best time for fertilizers, harvasting cutting, vaccination, rooting. | |
Conditionally fertile: Scorpio | |
Neutral: Aries, Leo, Sagittarius, Capricorn | |
Conditionally sterile: Libra | |
Sterile: Gemini, Virgo, Aquarius | |
Fertility indices ranges from 0.0 to 3.0 where proportionaly | |
0 - minimal expected fertility | |
3.0 - most favorable fertility for platining, | |
and depends on type of plant (root crop or produce above ground). | |
Pruning indices ranges from 0 to 3 where proportionaly: | |
0 - pruning is not recommended as it causes most damage to tree and can lead to: | |
Increased sap production from the cut points | |
Increased vulnerability to infections | |
Delayed wound healing | |
Possible weakening of the plant. | |
Instead of pruning into fertile signs, you can do: | |
Crown formation | |
Pinching the shoots | |
Removing dead branches | |
Sanitary treatment | |
1.0 - pruning is not recommended, | |
2.0 - allowed only minimum or sanitary pruning, | |
3.0 - most favorable time for pruning. | |
Args: | |
date_time (str): ISO 8601 formatted datetime (YYYY-MM-DDTHH:MM:SS) | |
Returns: | |
dict: { | |
"zodiac_position": "Leo 15°30'", | |
"moon_phase": "Waxing Gibbous", | |
"fertility_above_ground": 2.0, | |
"fertility_root_crop": 1.5, | |
"pruning": 2.0 | |
} | |
""" | |
try: | |
# Parse input datetime and localize to UTC | |
user_time = datetime.datetime.strptime(date_time, "%Y-%m-%dT%H:%M:%S") | |
user_time = pytz.utc.localize(user_time) | |
# Use loaded ephemeris and timescale | |
t = ts.from_datetime(user_time) | |
# Define celestial bodies | |
earth = planets['earth'] | |
moon = planets['moon'] | |
sun = planets['sun'] | |
# Calculate Moon's ecliptic longitude | |
astrometric = earth.at(t).observe(moon) | |
ecliptic_lat, ecliptic_lon, distance = astrometric.ecliptic_latlon() | |
lon_deg = ecliptic_lon.degrees % 360 | |
# Calculate the phase angle using almanac.moon_phase | |
phase = almanac.moon_phase(planets, t) | |
phase_angle = phase.degrees | |
# Determine Zodiac sign and position | |
zodiac_sign = "Unknown" | |
position_degrees = 0 | |
for sign, start, end in ZODIAC_SIGNS: | |
if start <= lon_deg < end: | |
zodiac_sign = sign | |
position_degrees = lon_deg - start | |
break | |
# Format position to degrees and minutes | |
degrees = int(position_degrees) | |
minutes = int((position_degrees % 1) * 60) | |
position_str = f"{zodiac_sign} {degrees}°{minutes:02}'" | |
# Determine moon phase for display | |
moon_phase = "Unknown" | |
for phase, start, end in MOON_PHASES: | |
if start <= phase_angle < end: | |
moon_phase = phase | |
break | |
# Determine phase category for indices with 15° orbis for New and Full Moon | |
if (phase_angle >= 345 or phase_angle < 15): | |
phase_category = "New Moon" # 345° to 15° (30° total orbis) | |
elif 15 <= phase_angle < 165: | |
phase_category = "Waxing Moon" | |
elif 165 <= phase_angle < 195: | |
phase_category = "Full Moon" # 165° to 195° (30° total orbis) | |
elif 195 <= phase_angle < 345: | |
phase_category = "Waning Moon" | |
else: | |
phase_category = "Unknown" | |
# Calculate fertility and pruning indices | |
if zodiac_sign in FERTILITY_SIGN_COEFFS and phase_category in FERTILITY_PHASE_COEFFS_ABOVE: | |
fertility_above_ground = FERTILITY_SIGN_COEFFS[zodiac_sign] + FERTILITY_PHASE_COEFFS_ABOVE[phase_category] | |
fertility_root_crop = FERTILITY_SIGN_COEFFS[zodiac_sign] + FERTILITY_PHASE_COEFFS_ROOT[phase_category] | |
pruning = PRUNING_SIGN_COEFFS[zodiac_sign] + PRUNING_PHASE_COEFFS[phase_category] | |
else: | |
fertility_above_ground = None | |
fertility_root_crop = None | |
pruning = None | |
return { | |
"zodiac_position": position_str, | |
"moon_phase": moon_phase, | |
"fertility_above_ground": fertility_above_ground, | |
"fertility_root_crop": fertility_root_crop, | |
"pruning": pruning | |
} | |
except Exception as e: | |
raise ValueError(f"Error in get_moon_info: {str(e)}") | |
@tool | |
def get_current_time_in_timezone(timezone: str) -> str: | |
""" | |
Returns the current local time in the specified timezone with description. | |
Args: | |
timezone (str): A string representing a valid timezone (e.g., 'UTC') | |
Returns: | |
str: Formatted local time with timezone description | |
""" | |
try: | |
tz = pytz.timezone(timezone) | |
now = datetime.datetime.now(tz) | |
return f"Local time in {timezone}: {now.strftime('%Y-%m-%d %H:%M:%S')}" | |
except Exception as e: | |
return f"Error: {str(e)}" | |
@tool | |
def get_current_time_raw(timezone: str) -> str: | |
""" | |
Returns current local time in specified timezone as ISO 8601 string. | |
Args: | |
timezone (str): A string representing a valid timezone (e.g., 'UTC') | |
Returns: | |
str: Datetime in ISO 8601 format (YYYY-MM-DDTHH:MM:SS) | |
""" | |
try: | |
tz = pytz.timezone(timezone) | |
now = datetime.datetime.now(tz) | |
return now.strftime("%Y-%m-%dT%H:%M:%S") | |
except Exception as e: | |
return f"Error: {str(e)}" | |
# Model configuration | |
final_answer = FinalAnswerTool() | |
model = HfApiModel( | |
max_tokens=2096, | |
temperature=0.5, | |
model_id="https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud/", | |
custom_role_conversions=None, | |
) | |
# Load image tool from Hub | |
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) | |
# Load prompt templates | |
with open("prompts.yaml", 'r') as stream: | |
prompt_templates = yaml.safe_load(stream) | |
# Initialize agent with all tools | |
agent = CodeAgent( | |
model=model, | |
tools=[final_answer, get_moon_info, get_current_time_in_timezone, get_current_time_raw, image_generation_tool], | |
max_steps=6, | |
verbosity_level=1, | |
prompt_templates=prompt_templates | |
# execution_env=E2BSandbox( | |
# allowed_imports=["numpy", "pandas"], # Explicitly permitted packages | |
# blocked_imports=["subprocess"], # Prevent system access | |
# ), | |
# safe_mode=True, # Enable safe code execution | |
# timeout=10, # Seconds before execution timeout | |
# max_memory=512, # MB memory limit | |
# file_system_access=False, # Disable disk write access | |
# network_access=False, # Block network operations | |
# max_code_iterations=100, # Prevent infinite loops | |
) | |
if __name__ == "__main__": | |
GradioUI(agent).launch() | |
# Change to your username and repo name | |
# agent.push_to_hub('sergeyo7/Garden_Magus') |