-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/langchain agent #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,44 @@ | ||||||||||||||||||
| from vertexai import agent_engines, init | ||||||||||||||||||
| from langchain_google_vertexai import HarmBlockThreshold, HarmCategory | ||||||||||||||||||
|
|
||||||||||||||||||
| init(project="ai-agent-hackathon-3-471422", location="us-central1") | ||||||||||||||||||
|
Comment on lines
+3
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 [Security Risk]: The project ID is hardcoded in the code. This is a sensitive configuration that should be managed through environment variables or a secure configuration system1.
Suggested change
Footnotes
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoding the project ID and location can lead to issues when deploying to different environments (e.g., staging, production) and is a security risk if the repository is public. It's better to load these values from environment variables. You will need to add
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
| safety_settings = { | ||||||||||||||||||
| HarmCategory.HARM_CATEGORY_UNSPECIFIED: HarmBlockThreshold.BLOCK_NONE, | ||||||||||||||||||
| HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, | ||||||||||||||||||
| HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH, | ||||||||||||||||||
| HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE, | ||||||||||||||||||
| HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE, | ||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider setting SEXUALLY_EXPLICIT content blocking to at least BLOCK_MEDIUM_AND_ABOVE for better content safety. The current BLOCK_NONE setting might allow inappropriate content through. |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| model_kwargs = { | ||||||||||||||||||
| # temperature (float): The sampling temperature controls the degree of | ||||||||||||||||||
| # randomness in token selection. | ||||||||||||||||||
| "temperature": 0.28, | ||||||||||||||||||
| # max_output_tokens (int): The token limit determines the maximum amount of | ||||||||||||||||||
| # text output from one prompt. | ||||||||||||||||||
| "max_output_tokens": 1000, | ||||||||||||||||||
| # top_p (float): Tokens are selected from most probable to least until | ||||||||||||||||||
| # the sum of their probabilities equals the top-p value. | ||||||||||||||||||
| "top_p": 0.95, | ||||||||||||||||||
| # top_k (int): The next token is selected from among the top-k most | ||||||||||||||||||
| # probable tokens. This is not supported by all model versions. See | ||||||||||||||||||
| # https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/image-understanding#valid_parameter_values | ||||||||||||||||||
| # for details. | ||||||||||||||||||
| "top_k": None, | ||||||||||||||||||
| # safety_settings (Dict[HarmCategory, HarmBlockThreshold]): The safety | ||||||||||||||||||
| # settings to use for generating content. | ||||||||||||||||||
| # (you must create your safety settings using the previous step first). | ||||||||||||||||||
| "safety_settings": safety_settings, | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| model = "gemini-2.0-flash" | ||||||||||||||||||
|
|
||||||||||||||||||
| agent = agent_engines.LangchainAgent( | ||||||||||||||||||
| model=model, # Required. | ||||||||||||||||||
| model_kwargs=model_kwargs, # Optional. | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
| if __name__ == "__main__": | ||||||||||||||||||
| response = agent.query(input="What is the exchange rate from US dollars to SEK today?") | ||||||||||||||||||
| print(response) | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,54 @@ | ||||||||||||||||||||||||||||||||||||
| import ee | ||||||||||||||||||||||||||||||||||||
| import requests | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| def initialize_gee(): | ||||||||||||||||||||||||||||||||||||
| """認証と初期化。ローカル認証が必要な場合はee.Authenticate()を使う。""" | ||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||
| ee.Initialize() | ||||||||||||||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+6
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 [Error Handling]: The exception handling is too broad. Catching all exceptions can mask serious issues. Consider catching specific exceptions and adding proper error logging.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Catching a generic
Suggested change
|
||||||||||||||||||||||||||||||||||||
| ee.Authenticate() | ||||||||||||||||||||||||||||||||||||
| ee.Initialize() | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| def get_ndvi_image(lat, lon, start_date, end_date, out_path): | ||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||
| 指定座標・期間でNDVI画像を生成し、ファイル保存する。 | ||||||||||||||||||||||||||||||||||||
| Args: | ||||||||||||||||||||||||||||||||||||
| lat (float): 緯度 | ||||||||||||||||||||||||||||||||||||
| lon (float): 経度 | ||||||||||||||||||||||||||||||||||||
| start_date (str): 取得開始日(YYYY-MM-DD) | ||||||||||||||||||||||||||||||||||||
| end_date (str): 取得終了日(YYYY-MM-DD) | ||||||||||||||||||||||||||||||||||||
| out_path (str): 保存先ファイルパス | ||||||||||||||||||||||||||||||||||||
| Returns: | ||||||||||||||||||||||||||||||||||||
| out_path (str): 保存した画像ファイルパス | ||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||
| # Sentinel-2画像コレクション取得 | ||||||||||||||||||||||||||||||||||||
| point = ee.Geometry.Point([lon, lat]) | ||||||||||||||||||||||||||||||||||||
| collection = ee.ImageCollection('COPERNICUS/S2') \ | ||||||||||||||||||||||||||||||||||||
| .filterBounds(point) \ | ||||||||||||||||||||||||||||||||||||
| .filterDate(start_date, end_date) \ | ||||||||||||||||||||||||||||||||||||
| .sort('CLOUD_COVER') | ||||||||||||||||||||||||||||||||||||
| image = collection.first() | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
| image = collection.first() | |
| image = collection.first() | |
| if image is None: | |
| raise ValueError("No Sentinel-2 images found for the specified location and date range.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The collection.first() call might return None if no images are found for the given location and date range. This would cause an AttributeError when image.normalizedDifference is called. You should add a check to handle this case gracefully.
| image = collection.first() | |
| # NDVI計算 | |
| ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI') | |
| image = collection.first() | |
| if not image: | |
| raise ValueError("No image found for the specified criteria.") | |
| ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI') |
Copilot
AI
Sep 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The buffer distance (10000) and image dimensions (512) are magic numbers that should be defined as named constants or function parameters for better maintainability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot
AI
Sep 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HTTP request lacks error handling. If the request fails or returns a non-200 status code, the function will still attempt to write the response content to file, potentially creating invalid image files.
| r = requests.get(url) | |
| r = requests.get(url) | |
| try: | |
| r.raise_for_status() | |
| except requests.RequestException as e: | |
| raise RuntimeError(f"Failed to download NDVI image: {e}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛑 [Security Risk]: Writing files without path validation could lead to path traversal vulnerabilities1. Add validation for the out_path parameter.
| r = requests.get(url) | |
| with open(out_path, 'wb') as f: | |
| # Validate and sanitize file path | |
| safe_path = os.path.abspath(os.path.normpath(out_path)) | |
| if not safe_path.endswith('.png'): | |
| raise ValueError("Output path must end with .png") | |
| with open(safe_path, 'wb') as f: | |
| f.write(r.content) |
Footnotes
-
CWE-22: Improper Limitation of a Pathname to a Restricted Directory - https://cwe.mitre.org/data/definitions/22.html ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requests.get() call does not handle potential HTTP errors (e.g., 4xx or 5xx status codes). If the URL fetch fails, r.content might be an error page. It's good practice to check the response status. A simple way is to call r.raise_for_status() after the request, which will raise an HTTPError for bad responses.
| r = requests.get(url) | |
| with open(out_path, 'wb') as f: | |
| f.write(r.content) | |
| r = requests.get(url) | |
| r.raise_for_status() | |
| with open(out_path, 'wb') as f: | |
| f.write(r.content) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| firebase_functions~=0.1.0 | ||
| firebase_functions~=0.1.0 | ||
| earthengine-api | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider pinning dependency versions for better reproducibility and security. Unpinned dependencies can lead to unexpected behavior or vulnerabilities if a package releases breaking changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard-coded project ID should be moved to environment variables or configuration file to avoid exposing sensitive project information in source code.