feat/openai #1

Merged
tbs093a merged 2 commits from feat/openai into master 2025-05-14 13:20:22 +00:00
5 changed files with 316 additions and 41 deletions

View File

@ -1,5 +1,5 @@
import logging import logging
from typing import Optional from typing import Optional, Tuple, Dict, Any
from openai import AsyncOpenAI # Używamy AsyncOpenAI dla kompatybilności z asyncio from openai import AsyncOpenAI # Używamy AsyncOpenAI dla kompatybilności z asyncio
from .config import OPENAI_API_KEY, SUMMARY_PROMPT from .config import OPENAI_API_KEY, SUMMARY_PROMPT
@ -21,6 +21,10 @@ class SummarizationError(OpenAIUtilsError):
"""Wyjątek rzucany przy błędach streszczania tekstu.""" """Wyjątek rzucany przy błędach streszczania tekstu."""
pass pass
class QuotaExceededError(OpenAIUtilsError):
"""Wyjątek rzucany gdy przekroczono limit zapytań API."""
pass
# Inicjalizuj klienta OpenAI asynchronicznie # Inicjalizuj klienta OpenAI asynchronicznie
client = None client = None
try: try:
@ -32,6 +36,62 @@ except Exception as e:
logger.error(f"Błąd inicjalizacji klienta OpenAI: {e}", exc_info=True) logger.error(f"Błąd inicjalizacji klienta OpenAI: {e}", exc_info=True)
# Nie rzucamy tu wyjątku, bo to moment inicjalizacji modułu # Nie rzucamy tu wyjątku, bo to moment inicjalizacji modułu
async def check_openai_api_status() -> Tuple[bool, Dict[str, Any]]:
"""
Sprawdza status API OpenAI, w tym dostępne limity użycia.
Returns:
Krotka (status, info), gdzie status to True, jeśli API jest dostępne
i info to słownik z dodatkowymi informacjami o statusie
Raises:
APIKeyMissingError: Gdy brak klucza API OpenAI
QuotaExceededError: Gdy przekroczono limit zapytań API
"""
if not client:
logger.error("Klient OpenAI nie został zainicjalizowany.")
raise APIKeyMissingError("Klient OpenAI nie został zainicjalizowany. Sprawdź klucz API.")
try:
logger.info("Sprawdzanie statusu API OpenAI")
# Używamy prostego zapytania do sprawdzenia statusu konta
response = await client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "This is a test message to check API status."},
{"role": "user", "content": "Hello"}
],
max_tokens=5
)
# Sprawdzamy czy odpowiedź jest poprawna
if response and response.choices and len(response.choices) > 0:
status_info = {
"available": True,
"model": "gpt-4o-mini",
"usage": vars(response.usage) if hasattr(response, "usage") else {},
"organization_id": getattr(response, "organization_id", None)
}
logger.info(f"API OpenAI jest dostępne, użycie tokenów: {status_info['usage']}")
return True, status_info
else:
status_info = {"available": False, "error": "Nieprawidłowa odpowiedź API"}
logger.warning("API OpenAI zwróciło nieprawidłową odpowiedź podczas testu")
return False, status_info
except Exception as e:
error_message = str(e)
status_info = {"available": False, "error": error_message}
# Sprawdzamy czy to błąd limitu zapytań
if "429" in error_message or "quota" in error_message.lower() or "insufficient_quota" in error_message:
logger.error(f"Przekroczono limit zapytań API OpenAI: {e}")
raise QuotaExceededError(f"Przekroczono limit zapytań API OpenAI: {error_message}")
logger.error(f"Błąd podczas sprawdzania statusu API OpenAI: {e}", exc_info=True)
return False, status_info
async def summarize_text(text: str) -> str: async def summarize_text(text: str) -> str:
""" """
Wysyła tekst do API OpenAI w celu streszczenia. Wysyła tekst do API OpenAI w celu streszczenia.
@ -45,7 +105,8 @@ async def summarize_text(text: str) -> str:
Raises: Raises:
EmptyTextError: Gdy tekst jest pusty EmptyTextError: Gdy tekst jest pusty
APIKeyMissingError: Gdy brak klucza API OpenAI APIKeyMissingError: Gdy brak klucza API OpenAI
SummarizationError: Przy błędach API OpenAI QuotaExceededError: Gdy przekroczono limit zapytań API
SummarizationError: Przy innych błędach API OpenAI
""" """
if not text: if not text:
logger.warning("Próba streszczenia pustego tekstu.") logger.warning("Próba streszczenia pustego tekstu.")
@ -75,5 +136,11 @@ async def summarize_text(text: str) -> str:
return summary return summary
except Exception as e: except Exception as e:
error_message = str(e)
logger.error(f"Błąd API OpenAI podczas streszczania: {e}", exc_info=True) logger.error(f"Błąd API OpenAI podczas streszczania: {e}", exc_info=True)
# Sprawdzamy, czy to błąd limitu zapytań
if "429" in error_message or "quota" in error_message.lower() or "insufficient_quota" in error_message:
raise QuotaExceededError(f"Przekroczono limit zapytań API OpenAI: {error_message}")
raise SummarizationError(f"Błąd API OpenAI: {str(e)}") raise SummarizationError(f"Błąd API OpenAI: {str(e)}")

37
tests/check_env.py 100644
View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
"""
Prosty skrypt do sprawdzania dostępności zmiennych środowiskowych i API
przed uruchomieniem testów integracyjnych.
"""
import os
import sys
def main():
"""Wyświetla status zmiennych środowiskowych i informacje o testach"""
print("\n* Sprawdzanie zmiennych środowiskowych przed uruchomieniem testów:")
# Sprawdź YOUTUBE_TRANSCRIPT_API_TOKEN
has_youtube_token = bool(os.environ.get("YOUTUBE_TRANSCRIPT_API_TOKEN"))
youtube_status = "Ustawiony" if has_youtube_token else "BRAK - niektóre testy będą pominięte"
print(f" - YOUTUBE_TRANSCRIPT_API_TOKEN: {youtube_status}")
# Sprawdź OPENAI_API_KEY
has_openai_key = bool(os.environ.get("OPENAI_API_KEY"))
openai_status = "Ustawiony" if has_openai_key else "BRAK - testy OpenAI będą pominięte"
print(f" - OPENAI_API_KEY: {openai_status}")
print("\n* Informacje o testach:")
print(" - Testy integracyjne z OpenAI API sprawdzą dostępność API przed wykonaniem.")
print(" - Jeżeli limit API OpenAI został przekroczony, testy będą automatycznie pominięte.")
print(" - Testy dla YouTube API będą używać filmy 'What makes a good life?' lub 'Me at the zoo'.")
print()
if not has_youtube_token and not has_openai_key:
print("UWAGA: Brak kluczowych zmiennych środowiskowych dla testów integracyjnych!")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@ -6,7 +6,14 @@ import os
# Dodanie katalogu nadrzędnego do ścieżki dla importów # Dodanie katalogu nadrzędnego do ścieżki dla importów
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from src.openai_utils import summarize_text from src.openai_utils import (
summarize_text,
check_openai_api_status,
EmptyTextError,
APIKeyMissingError,
SummarizationError,
QuotaExceededError
)
@pytest.mark.asyncio @pytest.mark.asyncio
@ -27,17 +34,17 @@ async def test_summarize_text_success():
"Zawiera kilka zdań o różnej tematyce." "Zawiera kilka zdań o różnej tematyce."
# Test funkcji z mockiem # Test funkcji z mockiem
with patch('src.openai_utils.client.chat.completions.create', with patch('src.openai_utils.client') as mock_client:
new=AsyncMock(return_value=mock_response)) as mock_create: mock_client.chat.completions.create = AsyncMock(return_value=mock_response)
result = await summarize_text(test_transcript) result = await summarize_text(test_transcript)
# Sprawdzenie wyników # Sprawdzenie wyników
assert result == "To jest przykładowe streszczenie filmu." assert result == "To jest przykładowe streszczenie filmu."
assert mock_create.called assert mock_client.chat.completions.create.called
# Sprawdzenie czy parametry zostały przekazane poprawnie # Sprawdzenie czy parametry zostały przekazane poprawnie
call_args = mock_create.call_args[1] call_args = mock_client.chat.completions.create.call_args[1]
assert call_args['model'] == "gpt-3.5-turbo" assert call_args['model'] == "gpt-4o-mini" # Zaktualizowano model
assert call_args['temperature'] == 0.5 assert call_args['temperature'] == 0.5
assert call_args['max_tokens'] == 150 assert call_args['max_tokens'] == 150
@ -67,37 +74,66 @@ async def test_summarize_text_with_transcript_from_youtube():
"Przedstawia różne zastosowania AI w codziennym życiu." "Przedstawia różne zastosowania AI w codziennym życiu."
# Test funkcji # Test funkcji
with patch('src.openai_utils.client.chat.completions.create', with patch('src.openai_utils.client') as mock_client:
new=AsyncMock(return_value=mock_response)) as mock_create: mock_client.chat.completions.create = AsyncMock(return_value=mock_response)
result = await summarize_text(youtube_transcript) result = await summarize_text(youtube_transcript)
# Sprawdzenie wyników # Sprawdzenie wyników
assert result == "Film przedstawia dyskusję na temat sztucznej inteligencji i jej zastosowań w życiu codziennym." assert result == "Film przedstawia dyskusję na temat sztucznej inteligencji i jej zastosowań w życiu codziennym."
assert mock_create.called assert mock_client.chat.completions.create.called
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_summarize_empty_text(): async def test_summarize_empty_text():
# Test funkcji z pustym tekstem # Test funkcji z pustym tekstem
with patch('src.openai_utils.client.chat.completions.create') as mock_create: with patch('src.openai_utils.client.chat.completions.create') as mock_create:
result = await summarize_text("") # Powinien rzucić EmptyTextError dla pustego tekstu
with pytest.raises(EmptyTextError):
await summarize_text("")
# Sprawdzenie wyników # Sprawdzenie czy mock nie został wywołany
assert result is None
assert not mock_create.called assert not mock_create.called
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_summarize_text_api_error(): async def test_summarize_text_api_error():
# Symulacja błędu API # Symulacja błędu API
with patch('src.openai_utils.client.chat.completions.create', with patch('src.openai_utils.client') as mock_client:
new=AsyncMock(side_effect=Exception("API Error"))) as mock_create: mock_client.chat.completions.create = AsyncMock(side_effect=Exception("API Error"))
# Test funkcji
result = await summarize_text("Jakiś tekst transkrypcji")
# Sprawdzenie wyników # Test funkcji - powinien rzucić SummarizationError
assert result is None with pytest.raises(SummarizationError) as excinfo:
assert mock_create.called await summarize_text("Jakiś tekst transkrypcji")
# Sprawdzenie czy wiadomość błędu zawiera oryginalne informacje
assert "API Error" in str(excinfo.value)
assert mock_client.chat.completions.create.called
@pytest.mark.asyncio
async def test_summarize_text_quota_exceeded_error():
# Symulacja błędu przekroczenia limitu
error_response = Exception("Error code: 429 - {'error': {'message': 'You exceeded your current quota', 'type': 'insufficient_quota'}}")
with patch('src.openai_utils.client') as mock_client:
mock_client.chat.completions.create = AsyncMock(side_effect=error_response)
# Test funkcji - powinien rzucić QuotaExceededError
with pytest.raises(QuotaExceededError) as excinfo:
await summarize_text("Jakiś tekst transkrypcji")
# Sprawdzenie czy wiadomość błędu zawiera informację o limicie
assert "Przekroczono limit zapytań API OpenAI" in str(excinfo.value)
assert mock_client.chat.completions.create.called
@pytest.mark.asyncio
async def test_summarize_text_no_client():
# Symulacja braku klienta OpenAI
with patch('src.openai_utils.client', None):
# Test funkcji - powinien rzucić APIKeyMissingError
with pytest.raises(APIKeyMissingError):
await summarize_text("Jakiś tekst transkrypcji")
@pytest.mark.asyncio @pytest.mark.asyncio
@ -116,20 +152,94 @@ async def test_summarize_text_prompt_format():
test_transcript = "Testowa transkrypcja" test_transcript = "Testowa transkrypcja"
# Przygotowanie spy do przechwycenia argumentów # Przygotowanie spy do przechwycenia argumentów
with patch('src.openai_utils.client.chat.completions.create', with patch('src.openai_utils.client') as mock_client:
new=AsyncMock(return_value=mock_response)) as mock_create: mock_client.chat.completions.create = AsyncMock(return_value=mock_response)
# Test funkcji # Test funkcji
await summarize_text(test_transcript) await summarize_text(test_transcript)
# Sprawdzenie czy został wywołany # Sprawdzenie czy został wywołany
assert mock_create.called assert mock_client.chat.completions.create.called
# Pobranie argumentów wywołania # Pobranie argumentów wywołania
call_args = mock_create.call_args[1] call_args = mock_client.chat.completions.create.call_args[1]
messages = call_args['messages'] messages = call_args['messages']
# Sprawdzenie czy prompt zawiera odpowiedni format # Sprawdzenie czy prompt zawiera odpowiedni format
user_prompt = messages[1]['content'] user_prompt = messages[1]['content']
assert "Streść poniższy transkrypt filmu z YouTube" in user_prompt assert "Streść poniższy transkrypt filmu z YouTube" in user_prompt
assert "Transkrypt:" in user_prompt assert "Transkrypt:" in user_prompt
assert test_transcript in user_prompt assert test_transcript in user_prompt
@pytest.mark.asyncio
async def test_check_openai_api_status_success():
# Przygotowanie mocka dla udanej odpowiedzi
mock_choice = MagicMock()
mock_message = MagicMock()
mock_message.content = "Hello"
mock_choice.message = mock_message
mock_response = MagicMock()
mock_response.choices = [mock_choice]
mock_response.usage = MagicMock(_asdict=lambda: {"prompt_tokens": 20, "completion_tokens": 5, "total_tokens": 25})
mock_response.organization_id = "org-123"
with patch('src.openai_utils.client') as mock_client:
mock_client.chat.completions.create = AsyncMock(return_value=mock_response)
# Test funkcji
available, status_info = await check_openai_api_status()
# Sprawdzenie wyników
assert available == True
assert status_info["available"] == True
assert status_info["model"] == "gpt-4o-mini"
assert status_info["organization_id"] == "org-123"
assert "usage" in status_info
assert status_info["usage"]["total_tokens"] == 25
assert mock_client.chat.completions.create.called
@pytest.mark.asyncio
async def test_check_openai_api_status_quota_exceeded():
# Symulacja błędu przekroczenia limitu
error_response = Exception("Error code: 429 - {'error': {'message': 'You exceeded your current quota', 'type': 'insufficient_quota'}}")
with patch('src.openai_utils.client') as mock_client:
mock_client.chat.completions.create = AsyncMock(side_effect=error_response)
# Test funkcji - powinien rzucić QuotaExceededError
with pytest.raises(QuotaExceededError) as excinfo:
await check_openai_api_status()
# Sprawdzenie czy wiadomość błędu zawiera informację o limicie
assert "Przekroczono limit zapytań API OpenAI" in str(excinfo.value)
assert mock_client.chat.completions.create.called
@pytest.mark.asyncio
async def test_check_openai_api_status_no_client():
# Symulacja braku klienta OpenAI
with patch('src.openai_utils.client', None):
# Test funkcji - powinien rzucić APIKeyMissingError
with pytest.raises(APIKeyMissingError):
await check_openai_api_status()
@pytest.mark.asyncio
async def test_check_openai_api_status_api_error():
# Symulacja ogólnego błędu API
with patch('src.openai_utils.client') as mock_client:
mock_client.chat.completions.create = AsyncMock(side_effect=Exception("General API Error"))
# Test funkcji - nie powinien rzucać wyjątku
available, status_info = await check_openai_api_status()
# Sprawdzenie wyników
assert available == False
assert status_info["available"] == False
assert "error" in status_info
assert "General API Error" in status_info["error"]
assert mock_client.chat.completions.create.called

View File

@ -21,7 +21,7 @@ from src.youtube_utils import (
NoTranscriptLanguagesAvailable, NoTranscriptLanguagesAvailable,
YouTubeUtilsError YouTubeUtilsError
) )
from src.openai_utils import summarize_text from src.openai_utils import summarize_text, check_openai_api_status, QuotaExceededError
# Konfiguracja logowania dla testów # Konfiguracja logowania dla testów
logging.basicConfig( logging.basicConfig(
@ -44,10 +44,48 @@ TEST_LANGUAGES = ["pl", "en"] # Preferujemy polską transkrypcję, potem angiel
BACKUP_VIDEO_URL = "https://www.youtube.com/watch?v=jNQXAC9IVRw" # Me at the zoo - pierwszy film na YouTube BACKUP_VIDEO_URL = "https://www.youtube.com/watch?v=jNQXAC9IVRw" # Me at the zoo - pierwszy film na YouTube
BACKUP_VIDEO_ID = extract_video_id(BACKUP_VIDEO_URL) BACKUP_VIDEO_ID = extract_video_id(BACKUP_VIDEO_URL)
# Flaga określająca dostępność API OpenAI, inicjalizowana jako None (sprawdzana przed testami)
OPENAI_API_AVAILABLE = None
OPENAI_STATUS_INFO = {}
# Oznaczamy testy jako "slow", żeby można było je pominąć za pomocą --skip-slow # Oznaczamy testy jako "slow", żeby można było je pominąć za pomocą --skip-slow
# lub --skip-integration podczas uruchamiania testów # lub --skip-integration podczas uruchamiania testów
pytestmark = [pytest.mark.integration, pytest.mark.slow] pytestmark = [pytest.mark.integration, pytest.mark.slow]
# Helper do sprawdzania dostępności API OpenAI przed testami
async def ensure_openai_api_status():
"""Sprawdza status API OpenAI i ustawia globalną flagę OPENAI_API_AVAILABLE"""
global OPENAI_API_AVAILABLE, OPENAI_STATUS_INFO
# Jeśli nie ma klucza API, nie ma sensu sprawdzać
if not os.environ.get("OPENAI_API_KEY"):
logger.warning("Brak klucza API OpenAI, pomijam sprawdzanie statusu API")
OPENAI_API_AVAILABLE = False
OPENAI_STATUS_INFO = {"error": "Brak klucza API"}
return False
# Jeśli już sprawdziliśmy, używamy zapisanego wyniku
if OPENAI_API_AVAILABLE is not None:
return OPENAI_API_AVAILABLE
try:
logger.info("Sprawdzam dostępność API OpenAI...")
OPENAI_API_AVAILABLE, OPENAI_STATUS_INFO = await check_openai_api_status()
logger.info(f"Status API OpenAI: {'dostępne' if OPENAI_API_AVAILABLE else 'niedostępne'}")
if not OPENAI_API_AVAILABLE:
logger.warning(f"API OpenAI niedostępne: {OPENAI_STATUS_INFO.get('error', 'Nieznany błąd')}")
return OPENAI_API_AVAILABLE
except QuotaExceededError as e:
logger.warning(f"Przekroczono limit zapytań API OpenAI: {e}")
OPENAI_API_AVAILABLE = False
OPENAI_STATUS_INFO = {"error": str(e)}
return False
except Exception as e:
logger.error(f"Błąd podczas sprawdzania statusu API OpenAI: {e}", exc_info=True)
OPENAI_API_AVAILABLE = False
OPENAI_STATUS_INFO = {"error": str(e)}
return False
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_real_extract_youtube_urls(): async def test_real_extract_youtube_urls():
@ -127,10 +165,13 @@ async def test_real_get_transcript_and_title():
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.skipif(not os.environ.get("OPENAI_API_KEY"), reason="Wymaga klucza API OpenAI")
async def test_real_summarize_text(): async def test_real_summarize_text():
# Test rzeczywistego streszczania tekstu z OpenAI API # Test rzeczywistego streszczania tekstu z OpenAI API
# Ten test wymaga klucza API OpenAI # Ten test wymaga klucza API OpenAI i dostępnego API
# Sprawdź czy API OpenAI jest dostępne
if not await ensure_openai_api_status():
pytest.skip(f"API OpenAI niedostępne: {OPENAI_STATUS_INFO.get('error', 'Nieznany błąd')}")
# Użyjmy krótkiej transkrypcji dla oszczędności tokenów # Użyjmy krótkiej transkrypcji dla oszczędności tokenów
short_transcript = """ short_transcript = """
@ -151,19 +192,29 @@ async def test_real_summarize_text():
assert len(summary) > 0 assert len(summary) > 0
logger.info(f"Wygenerowane streszczenie: {summary}") logger.info(f"Wygenerowane streszczenie: {summary}")
except QuotaExceededError as e:
logger.warning(f"Przekroczono limit zapytań API OpenAI: {e}")
pytest.skip(f"Przekroczono limit zapytań API OpenAI: {e}")
except Exception as e: except Exception as e:
logger.error(f"Problem z API OpenAI: {e}", exc_info=True) logger.error(f"Problem z API OpenAI: {e}", exc_info=True)
pytest.skip(f"Problem z API OpenAI: {e}") pytest.skip(f"Problem z API OpenAI: {e}")
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.skipif(not os.environ.get("OPENAI_API_KEY") or not os.environ.get("YOUTUBE_TRANSCRIPT_API_TOKEN"),
reason="Wymaga klucza API OpenAI i tokenu API youtube-transcript.io")
async def test_end_to_end_integration(): async def test_end_to_end_integration():
""" """
Ten test wykonuje pełną integrację od linku YouTube do streszczenia. Ten test wykonuje pełną integrację od linku YouTube do streszczenia.
Wymaga dostępu do internetu, tokenu API youtube-transcript.io oraz klucza API OpenAI. Wymaga dostępu do internetu, tokenu API youtube-transcript.io oraz klucza API OpenAI.
""" """
# Sprawdź czy mamy token API youtube-transcript.io
from src.config import YOUTUBE_TRANSCRIPT_API_TOKEN
if not YOUTUBE_TRANSCRIPT_API_TOKEN:
pytest.skip("Brak tokenu API youtube-transcript.io")
# Sprawdź czy API OpenAI jest dostępne
if not await ensure_openai_api_status():
pytest.skip(f"API OpenAI niedostępne: {OPENAI_STATUS_INFO.get('error', 'Nieznany błąd')}")
logger.info("Rozpoczynam test integracyjny end-to-end") logger.info("Rozpoczynam test integracyjny end-to-end")
# Testujemy na klasycznym filmie "Me at the zoo", który jest krótki i ma dostępne transkrypcje # Testujemy na klasycznym filmie "Me at the zoo", który jest krótki i ma dostępne transkrypcje
@ -209,8 +260,7 @@ async def test_end_to_end_integration():
logger.error(f"Nie można pobrać transkrypcji dla żadnego z testowych filmów: {e}") logger.error(f"Nie można pobrać transkrypcji dla żadnego z testowych filmów: {e}")
pytest.skip(f"Nie można pobrać transkrypcji dla żadnego z testowych filmów: {e}") pytest.skip(f"Nie można pobrać transkrypcji dla żadnego z testowych filmów: {e}")
# 4. Skrócenie transkrypcji dla oszczędności tokenów (tylko dla testu) # 4. "Me at the zoo" ma wystarczająco krótką transkrypcję, więc możemy użyć całości
# "Me at the zoo" ma wystarczająco krótką transkrypcję, więc możemy użyć całości
logger.info(f"Długość oryginalnej transkrypcji: {len(transcript)} znaków") logger.info(f"Długość oryginalnej transkrypcji: {len(transcript)} znaków")
# 5. Wygenerowanie streszczenia # 5. Wygenerowanie streszczenia
@ -223,6 +273,9 @@ async def test_end_to_end_integration():
logger.info(f"Wygenerowane streszczenie: {summary}") logger.info(f"Wygenerowane streszczenie: {summary}")
except QuotaExceededError as e:
logger.warning(f"Przekroczono limit zapytań API OpenAI: {e}")
pytest.skip(f"Przekroczono limit zapytań API OpenAI: {e}")
except Exception as e: except Exception as e:
logger.error(f"Błąd podczas generowania streszczenia: {e}", exc_info=True) logger.error(f"Błąd podczas generowania streszczenia: {e}", exc_info=True)
pytest.skip(f"Błąd podczas generowania streszczenia: {e}") pytest.skip(f"Błąd podczas generowania streszczenia: {e}")
@ -241,13 +294,17 @@ if __name__ == "__main__":
# Testy wymagające klucza API OpenAI # Testy wymagające klucza API OpenAI
if os.environ.get("OPENAI_API_KEY"): if os.environ.get("OPENAI_API_KEY"):
try: asyncio.run(ensure_openai_api_status()) # Sprawdź status API przed uruchomieniem testów
asyncio.run(test_real_summarize_text()) if OPENAI_API_AVAILABLE:
if os.environ.get("YOUTUBE_TRANSCRIPT_API_TOKEN"): try:
asyncio.run(test_end_to_end_integration()) asyncio.run(test_real_summarize_text())
else: if os.environ.get("YOUTUBE_TRANSCRIPT_API_TOKEN"):
logger.warning("Pominięto test end-to-end (brak tokenu API youtube-transcript.io)") asyncio.run(test_end_to_end_integration())
except Exception as e: else:
logger.error(f"Problemy z OpenAI API: {e}", exc_info=True) logger.warning("Pominięto test end-to-end (brak tokenu API youtube-transcript.io)")
except Exception as e:
logger.error(f"Problemy z OpenAI API: {e}", exc_info=True)
else:
logger.warning(f"Pominięto testy OpenAI (API niedostępne: {OPENAI_STATUS_INFO.get('error')})")
else: else:
logger.warning("Pominięto testy OpenAI (brak klucza API)") logger.warning("Pominięto testy OpenAI (brak klucza API)")

View File

@ -77,6 +77,8 @@ pass_env =
DATABASE_URL DATABASE_URL
YOUTUBE_TRANSCRIPT_API_TOKEN YOUTUBE_TRANSCRIPT_API_TOKEN
commands = commands =
# Sprawdzenie zmiennych środowiskowych przed uruchomieniem testów
python tests/check_env.py
# Uruchamianie testów integracyjnych z rozszerzonym logowaniem # Uruchamianie testów integracyjnych z rozszerzonym logowaniem
python -m pytest tests/test_real_integration.py -v --log-cli-level=DEBUG python -m pytest tests/test_real_integration.py -v --log-cli-level=DEBUG
@ -104,6 +106,8 @@ pass_env =
DATABASE_URL DATABASE_URL
YOUTUBE_TRANSCRIPT_API_TOKEN YOUTUBE_TRANSCRIPT_API_TOKEN
commands = commands =
# Sprawdzenie zmiennych środowiskowych przed uruchomieniem testów
python tests/check_env.py
# Uruchamianie wszystkich testów # Uruchamianie wszystkich testów
python -m pytest tests/ --log-cli-level=INFO python -m pytest tests/ --log-cli-level=INFO