All checks were successful
continuous-integration/drone/push Build is passing
247 lines
9.1 KiB
Python
Executable File
247 lines
9.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""
|
||
Скрипт для тестирования API FatSecret
|
||
Выполняет тестовые запросы к API FatSecret с использованием ключей из конфигурации приложения
|
||
"""
|
||
|
||
import os
|
||
import json
|
||
import time
|
||
import base64
|
||
import requests
|
||
import urllib.parse
|
||
from dotenv import load_dotenv
|
||
|
||
# Загружаем .env файл
|
||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||
env_path = os.path.join(current_dir, ".env")
|
||
load_dotenv(env_path)
|
||
print(f"✅ Loaded .env from: {env_path}")
|
||
|
||
# Получаем API ключи из переменных окружения
|
||
FATSECRET_CLIENT_ID = os.environ.get("FATSECRET_CLIENT_ID")
|
||
FATSECRET_CLIENT_SECRET = os.environ.get("FATSECRET_CLIENT_SECRET")
|
||
|
||
if not FATSECRET_CLIENT_ID or not FATSECRET_CLIENT_SECRET:
|
||
raise ValueError("FatSecret API keys not found in .env file")
|
||
|
||
print(f"🔑 Using FatSecret API keys: CLIENT_ID={FATSECRET_CLIENT_ID[:8]}...")
|
||
customer_key = os.environ.get("FATSECRET_CUSTOMER_KEY")
|
||
if customer_key:
|
||
print(f"🔑 Using CUSTOMER_KEY={customer_key[:8]}...")
|
||
|
||
|
||
def get_oauth_token():
|
||
"""Получение OAuth 2.0 токена для доступа к API"""
|
||
print("🔄 Getting OAuth token...")
|
||
|
||
# Создаем заголовок авторизации с Base64-кодированными ID и секретом
|
||
auth_string = f"{FATSECRET_CLIENT_ID}:{FATSECRET_CLIENT_SECRET}"
|
||
auth_header = base64.b64encode(auth_string.encode()).decode()
|
||
|
||
# Полный вывод учетных данных для диагностики
|
||
print(f"🔑 CLIENT_ID: {FATSECRET_CLIENT_ID}")
|
||
if FATSECRET_CLIENT_SECRET:
|
||
print(f"🔑 CLIENT_SECRET (first few chars): {FATSECRET_CLIENT_SECRET[:5]}...")
|
||
else:
|
||
print("⚠️ CLIENT_SECRET is missing!")
|
||
print(f"🔑 Authorization header: Basic {auth_header}")
|
||
|
||
# Выполняем запрос на получение токена
|
||
token_url = "https://oauth.fatsecret.com/connect/token"
|
||
headers = {
|
||
"Authorization": f"Basic {auth_header}",
|
||
"Content-Type": "application/x-www-form-urlencoded"
|
||
}
|
||
data = {
|
||
"grant_type": "client_credentials",
|
||
"scope": "basic"
|
||
}
|
||
|
||
print("📤 Sending request with headers:")
|
||
for key, value in headers.items():
|
||
print(f" {key}: {value if key != 'Authorization' else value[:30]}...")
|
||
print("📤 Sending request with data:")
|
||
for key, value in data.items():
|
||
print(f" {key}: {value}")
|
||
|
||
try:
|
||
response = requests.post(token_url, headers=headers, data=data)
|
||
|
||
# Дополнительная информация о запросе
|
||
print(f"📥 Response status code: {response.status_code}")
|
||
print(f"📥 Response headers: {dict(response.headers)}")
|
||
|
||
# Проверяем успешность запроса
|
||
if response.status_code == 200:
|
||
token_data = response.json()
|
||
access_token = token_data.get("access_token")
|
||
expires_in = token_data.get("expires_in")
|
||
print(f"✅ Got token, expires in {expires_in} seconds")
|
||
return access_token
|
||
else:
|
||
print(f"❌ Error getting token: {response.status_code}")
|
||
print(f"❌ Error response: {response.text}")
|
||
return None
|
||
except Exception as e:
|
||
print(f"❌ Exception getting token: {e}")
|
||
return None
|
||
|
||
|
||
def search_food(token, query, max_results=5):
|
||
"""Поиск продуктов по названию"""
|
||
if not token:
|
||
print("⚠️ No token available, cannot search")
|
||
return None
|
||
|
||
print(f"🔍 Searching for '{query}'...")
|
||
|
||
api_url = "https://platform.fatsecret.com/rest/server.api"
|
||
headers = {
|
||
"Authorization": f"Bearer {token}",
|
||
"Content-Type": "application/json"
|
||
}
|
||
|
||
params = {
|
||
"method": "foods.search",
|
||
"search_expression": query,
|
||
"max_results": max_results,
|
||
"format": "json"
|
||
}
|
||
|
||
try:
|
||
response = requests.post(api_url, headers=headers, json=params)
|
||
|
||
if response.status_code == 200:
|
||
print(f"✅ Search successful")
|
||
result = response.json()
|
||
return result
|
||
else:
|
||
print(f"❌ Error searching: {response.status_code}")
|
||
print(response.text)
|
||
return None
|
||
except Exception as e:
|
||
print(f"❌ Exception during search: {e}")
|
||
return None
|
||
|
||
|
||
def get_food_details(token, food_id):
|
||
"""Получение информации о продукте по ID"""
|
||
if not token:
|
||
print("⚠️ No token available, cannot get food details")
|
||
return None
|
||
|
||
print(f"🔍 Getting details for food ID: {food_id}")
|
||
|
||
api_url = "https://platform.fatsecret.com/rest/server.api"
|
||
headers = {
|
||
"Authorization": f"Bearer {token}",
|
||
"Content-Type": "application/json"
|
||
}
|
||
|
||
params = {
|
||
"method": "food.get",
|
||
"food_id": food_id,
|
||
"format": "json"
|
||
}
|
||
|
||
try:
|
||
response = requests.post(api_url, headers=headers, json=params)
|
||
|
||
if response.status_code == 200:
|
||
print(f"✅ Got food details")
|
||
result = response.json()
|
||
return result
|
||
else:
|
||
print(f"❌ Error getting food details: {response.status_code}")
|
||
print(response.text)
|
||
return None
|
||
except Exception as e:
|
||
print(f"❌ Exception getting food details: {e}")
|
||
return None
|
||
|
||
|
||
def main():
|
||
"""Основная функция для тестирования API FatSecret"""
|
||
print("\n🚀 Starting FatSecret API test...\n")
|
||
|
||
# Получаем токен доступа
|
||
token = get_oauth_token()
|
||
|
||
if not token:
|
||
print("❌ Failed to get OAuth token, exiting")
|
||
return
|
||
|
||
# Тестируем поиск продуктов
|
||
print("\n--- 📋 Testing Food Search ---")
|
||
search_queries = ["apple", "bread", "chicken breast", "молоко"]
|
||
first_food_id = None
|
||
|
||
for query in search_queries:
|
||
result = search_food(token, query)
|
||
|
||
if result and "foods" in result:
|
||
foods_data = result["foods"]
|
||
|
||
if "food" not in foods_data:
|
||
print(f"⚠️ No results found for '{query}'")
|
||
continue
|
||
|
||
food_list = foods_data["food"]
|
||
if not isinstance(food_list, list):
|
||
food_list = [food_list] # Если только один результат, оборачиваем в список
|
||
|
||
print(f"📊 Found {len(food_list)} results")
|
||
|
||
# Выводим первые 3 результата
|
||
for i, food in enumerate(food_list[:3]):
|
||
food_name = food.get("food_name", "Unknown")
|
||
food_id = food.get("food_id", "Unknown")
|
||
food_desc = food.get("food_description", "No description")
|
||
|
||
print(f" {i+1}. [{food_id}] {food_name}")
|
||
print(f" {food_desc}")
|
||
|
||
# Сохраняем ID первого продукта для следующего теста
|
||
if not first_food_id and food_list:
|
||
first_food_id = food_list[0].get("food_id")
|
||
|
||
# Тестируем получение информации о продукте
|
||
if first_food_id:
|
||
print("\n--- 🍎 Testing Food Details ---")
|
||
food_details = get_food_details(token, first_food_id)
|
||
|
||
if food_details and "food" in food_details:
|
||
food = food_details["food"]
|
||
food_name = food.get("food_name", "Unknown")
|
||
brand = food.get("brand_name", "Generic")
|
||
|
||
print(f"📝 Details for: {food_name} [{brand}]")
|
||
|
||
# Выводим информацию о пищевой ценности
|
||
if "servings" in food:
|
||
servings = food["servings"]
|
||
if "serving" in servings:
|
||
serving_data = servings["serving"]
|
||
if not isinstance(serving_data, list):
|
||
serving_data = [serving_data]
|
||
|
||
print("\n📊 Nutrition info per serving:")
|
||
for i, serving in enumerate(serving_data[:2]): # Выводим до 2 видов порций
|
||
serving_desc = serving.get("serving_description", "Standard")
|
||
calories = serving.get("calories", "N/A")
|
||
protein = serving.get("protein", "N/A")
|
||
carbs = serving.get("carbohydrate", "N/A")
|
||
fat = serving.get("fat", "N/A")
|
||
|
||
print(f" Serving {i+1}: {serving_desc}")
|
||
print(f" Calories: {calories}")
|
||
print(f" Protein: {protein}g")
|
||
print(f" Carbohydrates: {carbs}g")
|
||
print(f" Fat: {fat}g")
|
||
|
||
print("\n✅ Test completed!")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |