SEO Dashboard Fixes and content planning refactoring
This commit is contained in:
@@ -16,7 +16,7 @@ from tenacity import (
|
||||
)
|
||||
|
||||
# Import APIKeyManager
|
||||
from ..api_key_manager import APIKeyManager
|
||||
from ..onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
try:
|
||||
import anthropic
|
||||
|
||||
@@ -70,11 +70,10 @@ from google.genai import types
|
||||
|
||||
|
||||
from loguru import logger
|
||||
logger.remove()
|
||||
logger.add(sys.stdout,
|
||||
colorize=True,
|
||||
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}"
|
||||
)
|
||||
from utils.logger_utils import get_service_logger
|
||||
|
||||
# Use service-specific logger to avoid conflicts
|
||||
logger = get_service_logger("gemini_audio_text")
|
||||
|
||||
|
||||
def load_environment():
|
||||
|
||||
@@ -18,7 +18,7 @@ from tenacity import (
|
||||
from .gemini_audio_text import transcribe_audio
|
||||
|
||||
# Import APIKeyManager
|
||||
from ...api_key_manager import APIKeyManager
|
||||
from ...onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
|
||||
def progress_function(stream, chunk, bytes_remaining):
|
||||
|
||||
@@ -16,7 +16,7 @@ from tenacity import (
|
||||
)
|
||||
|
||||
# Import APIKeyManager
|
||||
from ..api_key_manager import APIKeyManager
|
||||
from ..onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
try:
|
||||
import openai
|
||||
|
||||
@@ -131,30 +131,49 @@ class GeminiGroundedProvider:
|
||||
)
|
||||
self._cache[cache_key] = response
|
||||
except asyncio.TimeoutError:
|
||||
raise Exception(f"Gemini API request timed out after {self.timeout} seconds")
|
||||
from services.blog_writer.exceptions import APITimeoutException
|
||||
raise APITimeoutException(
|
||||
f"Gemini API request timed out after {self.timeout} seconds",
|
||||
timeout_seconds=self.timeout,
|
||||
context={"content_type": content_type, "model_id": model_id}
|
||||
)
|
||||
except Exception as api_error:
|
||||
# Handle specific Google API errors with retry logic
|
||||
# Handle specific Google API errors with enhanced retry logic
|
||||
error_str = str(api_error)
|
||||
if "503" in error_str and "overloaded" in error_str:
|
||||
# Conservative retry for overloaded service (expensive API calls)
|
||||
response = await self._retry_with_backoff(
|
||||
lambda: self._make_api_request_with_model(grounded_prompt, config, model_id, urls),
|
||||
max_retries=1, # Only 1 retry to avoid excessive costs
|
||||
base_delay=5 # Longer delay
|
||||
|
||||
# Non-retryable errors
|
||||
if "401" in error_str or "403" in error_str:
|
||||
from services.blog_writer.exceptions import ValidationException
|
||||
raise ValidationException(
|
||||
"Authentication failed. Please check your API credentials.",
|
||||
field="api_key",
|
||||
context={"error": error_str, "content_type": content_type}
|
||||
)
|
||||
elif "429" in error_str:
|
||||
# Conservative retry for rate limits
|
||||
response = await self._retry_with_backoff(
|
||||
lambda: self._make_api_request_with_model(grounded_prompt, config, model_id, urls),
|
||||
max_retries=1, # Only 1 retry
|
||||
base_delay=10 # Much longer delay for rate limits
|
||||
)
|
||||
elif "401" in error_str or "403" in error_str:
|
||||
raise Exception("Authentication failed. Please check your API credentials.")
|
||||
elif "400" in error_str:
|
||||
raise Exception("Invalid request. Please check your input parameters.")
|
||||
else:
|
||||
raise Exception(f"Google AI service error: {error_str}")
|
||||
from services.blog_writer.exceptions import ValidationException
|
||||
raise ValidationException(
|
||||
"Invalid request. Please check your input parameters.",
|
||||
field="request",
|
||||
context={"error": error_str, "content_type": content_type}
|
||||
)
|
||||
|
||||
# Retryable errors - use enhanced retry logic
|
||||
from services.blog_writer.retry_utils import retry_with_backoff, RESEARCH_RETRY_CONFIG
|
||||
|
||||
try:
|
||||
response = await retry_with_backoff(
|
||||
lambda: self._make_api_request_with_model(grounded_prompt, config, model_id, urls),
|
||||
config=RESEARCH_RETRY_CONFIG,
|
||||
operation_name=f"gemini_grounded_{content_type}",
|
||||
context={"content_type": content_type, "model_id": model_id}
|
||||
)
|
||||
except Exception as retry_error:
|
||||
# If retry also failed, raise the original error with context
|
||||
from services.blog_writer.exceptions import ResearchFailedException
|
||||
raise ResearchFailedException(
|
||||
f"Google AI service error after retries: {error_str}",
|
||||
context={"original_error": error_str, "retry_error": str(retry_error), "content_type": content_type}
|
||||
)
|
||||
|
||||
# Process the grounded response
|
||||
result = self._process_grounded_response(response, content_type)
|
||||
|
||||
@@ -77,11 +77,10 @@ else:
|
||||
print(f"No .env found at {env_path}, using current directory")
|
||||
|
||||
from loguru import logger
|
||||
logger.remove()
|
||||
logger.add(sys.stdout,
|
||||
colorize=True,
|
||||
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}"
|
||||
)
|
||||
from utils.logger_utils import get_service_logger
|
||||
|
||||
# Use service-specific logger to avoid conflicts
|
||||
logger = get_service_logger("gemini_provider")
|
||||
from tenacity import (
|
||||
retry,
|
||||
stop_after_attempt,
|
||||
@@ -389,17 +388,65 @@ def gemini_structured_json_response(prompt, schema, temperature=0.7, top_p=0.9,
|
||||
)
|
||||
|
||||
logger.info("🚀 Making Gemini API call...")
|
||||
try:
|
||||
response = client.models.generate_content(
|
||||
|
||||
# Use enhanced retry logic for structured JSON calls
|
||||
from services.blog_writer.retry_utils import retry_with_backoff, CONTENT_RETRY_CONFIG
|
||||
|
||||
async def make_api_call():
|
||||
return client.models.generate_content(
|
||||
model="gemini-2.5-flash",
|
||||
contents=prompt,
|
||||
config=generation_config,
|
||||
)
|
||||
|
||||
try:
|
||||
# Convert sync call to async for retry logic
|
||||
import asyncio
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
response = loop.run_until_complete(
|
||||
retry_with_backoff(
|
||||
make_api_call,
|
||||
config=CONTENT_RETRY_CONFIG,
|
||||
operation_name="gemini_structured_json",
|
||||
context={"schema_type": type(types_schema).__name__, "max_tokens": max_tokens}
|
||||
)
|
||||
)
|
||||
logger.info("✅ Gemini API call completed successfully")
|
||||
except Exception as api_error:
|
||||
logger.error(f"❌ Gemini API call failed: {api_error}")
|
||||
logger.error(f"❌ API Error type: {type(api_error).__name__}")
|
||||
raise api_error
|
||||
|
||||
# Enhance error with specific exception types
|
||||
error_str = str(api_error)
|
||||
if "429" in error_str or "rate limit" in error_str.lower():
|
||||
from services.blog_writer.exceptions import APIRateLimitException
|
||||
raise APIRateLimitException(
|
||||
f"Rate limit exceeded for structured JSON generation: {error_str}",
|
||||
retry_after=60,
|
||||
context={"operation": "structured_json", "max_tokens": max_tokens}
|
||||
)
|
||||
elif "timeout" in error_str.lower():
|
||||
from services.blog_writer.exceptions import APITimeoutException
|
||||
raise APITimeoutException(
|
||||
f"Structured JSON generation timed out: {error_str}",
|
||||
timeout_seconds=60,
|
||||
context={"operation": "structured_json", "max_tokens": max_tokens}
|
||||
)
|
||||
elif "401" in error_str or "403" in error_str:
|
||||
from services.blog_writer.exceptions import ValidationException
|
||||
raise ValidationException(
|
||||
"Authentication failed for structured JSON generation. Please check your API credentials.",
|
||||
field="api_key",
|
||||
context={"error": error_str, "operation": "structured_json"}
|
||||
)
|
||||
else:
|
||||
from services.blog_writer.exceptions import ContentGenerationException
|
||||
raise ContentGenerationException(
|
||||
f"Structured JSON generation failed: {error_str}",
|
||||
context={"error": error_str, "operation": "structured_json", "max_tokens": max_tokens}
|
||||
)
|
||||
|
||||
# Check for parsed content first (primary method for structured output)
|
||||
if hasattr(response, 'parsed'):
|
||||
|
||||
@@ -15,14 +15,13 @@ from google.genai import types
|
||||
|
||||
from PIL import Image
|
||||
from loguru import logger
|
||||
logger.remove()
|
||||
logger.add(sys.stdout,
|
||||
colorize=True,
|
||||
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}"
|
||||
)
|
||||
from utils.logger_utils import get_service_logger
|
||||
|
||||
# Use service-specific logger to avoid conflicts
|
||||
logger = get_service_logger("gemini_image_describe")
|
||||
|
||||
# Import APIKeyManager
|
||||
from ...api_key_manager import APIKeyManager
|
||||
from ...onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
try:
|
||||
import google.generativeai as genai
|
||||
|
||||
@@ -8,7 +8,7 @@ import os
|
||||
import json
|
||||
from typing import Optional, Dict, Any
|
||||
from loguru import logger
|
||||
from ..api_key_manager import APIKeyManager
|
||||
from ..onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
from .openai_provider import openai_chatgpt
|
||||
from .gemini_provider import gemini_text_response, gemini_structured_json_response
|
||||
|
||||
@@ -17,7 +17,7 @@ from tenacity import (
|
||||
)
|
||||
|
||||
# Import APIKeyManager
|
||||
from ..api_key_manager import APIKeyManager
|
||||
from ..onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
async def test_openai_api_key(api_key: str) -> Tuple[bool, str]:
|
||||
"""
|
||||
|
||||
@@ -10,7 +10,7 @@ from io import BytesIO
|
||||
import logging
|
||||
|
||||
# Import APIKeyManager
|
||||
from ...api_key_manager import APIKeyManager
|
||||
from ...onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
try:
|
||||
from google import genai
|
||||
|
||||
@@ -12,7 +12,7 @@ import streamlit as st
|
||||
from loguru import logger
|
||||
|
||||
# Import APIKeyManager
|
||||
from ...api_key_manager import APIKeyManager
|
||||
from ...onboarding.api_key_manager import APIKeyManager
|
||||
|
||||
def save_generated_image(data):
|
||||
"""Save the generated image to a file."""
|
||||
|
||||
@@ -15,11 +15,10 @@ import streamlit as st
|
||||
|
||||
import openai # OpenAI Python library to make API calls
|
||||
from loguru import logger
|
||||
logger.remove()
|
||||
logger.add(sys.stdout,
|
||||
colorize=True,
|
||||
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}"
|
||||
)
|
||||
from utils.logger_utils import get_service_logger
|
||||
|
||||
# Use service-specific logger to avoid conflicts
|
||||
logger = get_service_logger("text_to_image_generation")
|
||||
|
||||
#from .gen_dali2_images
|
||||
from .gen_dali3_images import generate_dalle3_images
|
||||
|
||||
Reference in New Issue
Block a user