255 lines
8.3 KiB
Python
255 lines
8.3 KiB
Python
"""
|
|
Simple validation script for LinkedIn content generation structure.
|
|
This script validates the code structure without requiring external dependencies.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import ast
|
|
import traceback
|
|
from pathlib import Path
|
|
|
|
def validate_file_syntax(file_path: str) -> bool:
|
|
"""Validate Python file syntax."""
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
ast.parse(content)
|
|
print(f"✅ {file_path}: Syntax valid")
|
|
return True
|
|
except SyntaxError as e:
|
|
print(f"❌ {file_path}: Syntax error - {e}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"❌ {file_path}: Error - {e}")
|
|
return False
|
|
|
|
def validate_import_structure(file_path: str) -> bool:
|
|
"""Validate import structure without actually importing."""
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
tree = ast.parse(content)
|
|
imports = []
|
|
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.Import):
|
|
for alias in node.names:
|
|
imports.append(alias.name)
|
|
elif isinstance(node, ast.ImportFrom):
|
|
module = node.module or ""
|
|
for alias in node.names:
|
|
imports.append(f"{module}.{alias.name}")
|
|
|
|
print(f"✅ {file_path}: Found {len(imports)} imports")
|
|
return True
|
|
except Exception as e:
|
|
print(f"❌ {file_path}: Import validation error - {e}")
|
|
return False
|
|
|
|
def check_class_structure(file_path: str, expected_classes: list) -> bool:
|
|
"""Check if expected classes are defined."""
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
tree = ast.parse(content)
|
|
found_classes = []
|
|
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.ClassDef):
|
|
found_classes.append(node.name)
|
|
|
|
missing_classes = set(expected_classes) - set(found_classes)
|
|
if missing_classes:
|
|
print(f"⚠️ {file_path}: Missing classes: {missing_classes}")
|
|
else:
|
|
print(f"✅ {file_path}: All expected classes found")
|
|
|
|
print(f" Found classes: {found_classes}")
|
|
return len(missing_classes) == 0
|
|
except Exception as e:
|
|
print(f"❌ {file_path}: Class validation error - {e}")
|
|
return False
|
|
|
|
def check_function_structure(file_path: str, expected_functions: list) -> bool:
|
|
"""Check if expected functions are defined."""
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
tree = ast.parse(content)
|
|
found_functions = []
|
|
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.FunctionDef):
|
|
found_functions.append(node.name)
|
|
elif isinstance(node, ast.AsyncFunctionDef):
|
|
found_functions.append(node.name)
|
|
|
|
missing_functions = set(expected_functions) - set(found_functions)
|
|
if missing_functions:
|
|
print(f"⚠️ {file_path}: Missing functions: {missing_functions}")
|
|
else:
|
|
print(f"✅ {file_path}: All expected functions found")
|
|
|
|
return len(missing_functions) == 0
|
|
except Exception as e:
|
|
print(f"❌ {file_path}: Function validation error - {e}")
|
|
return False
|
|
|
|
def validate_linkedin_models():
|
|
"""Validate LinkedIn models file."""
|
|
print("\n🔍 Validating LinkedIn Models")
|
|
print("-" * 40)
|
|
|
|
file_path = "models/linkedin_models.py"
|
|
if not os.path.exists(file_path):
|
|
print(f"❌ {file_path}: File does not exist")
|
|
return False
|
|
|
|
# Check syntax
|
|
syntax_ok = validate_file_syntax(file_path)
|
|
|
|
# Check imports
|
|
imports_ok = validate_import_structure(file_path)
|
|
|
|
# Check expected classes
|
|
expected_classes = [
|
|
"LinkedInPostRequest", "LinkedInArticleRequest", "LinkedInCarouselRequest",
|
|
"LinkedInVideoScriptRequest", "LinkedInCommentResponseRequest",
|
|
"LinkedInPostResponse", "LinkedInArticleResponse", "LinkedInCarouselResponse",
|
|
"LinkedInVideoScriptResponse", "LinkedInCommentResponseResult",
|
|
"PostContent", "ArticleContent", "CarouselContent", "VideoScript"
|
|
]
|
|
classes_ok = check_class_structure(file_path, expected_classes)
|
|
|
|
return syntax_ok and imports_ok and classes_ok
|
|
|
|
def validate_linkedin_service():
|
|
"""Validate LinkedIn service file."""
|
|
print("\n🔍 Validating LinkedIn Service")
|
|
print("-" * 40)
|
|
|
|
file_path = "services/linkedin_service.py"
|
|
if not os.path.exists(file_path):
|
|
print(f"❌ {file_path}: File does not exist")
|
|
return False
|
|
|
|
# Check syntax
|
|
syntax_ok = validate_file_syntax(file_path)
|
|
|
|
# Check imports
|
|
imports_ok = validate_import_structure(file_path)
|
|
|
|
# Check expected classes
|
|
expected_classes = ["LinkedInContentService"]
|
|
classes_ok = check_class_structure(file_path, expected_classes)
|
|
|
|
# Check expected methods
|
|
expected_functions = [
|
|
"generate_post", "generate_article", "generate_carousel",
|
|
"generate_video_script", "generate_comment_response"
|
|
]
|
|
functions_ok = check_function_structure(file_path, expected_functions)
|
|
|
|
return syntax_ok and imports_ok and classes_ok and functions_ok
|
|
|
|
def validate_linkedin_router():
|
|
"""Validate LinkedIn router file."""
|
|
print("\n🔍 Validating LinkedIn Router")
|
|
print("-" * 40)
|
|
|
|
file_path = "routers/linkedin.py"
|
|
if not os.path.exists(file_path):
|
|
print(f"❌ {file_path}: File does not exist")
|
|
return False
|
|
|
|
# Check syntax
|
|
syntax_ok = validate_file_syntax(file_path)
|
|
|
|
# Check imports
|
|
imports_ok = validate_import_structure(file_path)
|
|
|
|
# Check expected functions (endpoints)
|
|
expected_functions = [
|
|
"health_check", "generate_post", "generate_article",
|
|
"generate_carousel", "generate_video_script", "generate_comment_response",
|
|
"get_content_types", "get_usage_stats"
|
|
]
|
|
functions_ok = check_function_structure(file_path, expected_functions)
|
|
|
|
return syntax_ok and imports_ok and functions_ok
|
|
|
|
def check_file_exists(file_path: str) -> bool:
|
|
"""Check if file exists."""
|
|
exists = os.path.exists(file_path)
|
|
status = "✅" if exists else "❌"
|
|
print(f"{status} {file_path}: {'Exists' if exists else 'Missing'}")
|
|
return exists
|
|
|
|
def validate_file_structure():
|
|
"""Validate the overall file structure."""
|
|
print("\n🔍 Validating File Structure")
|
|
print("-" * 40)
|
|
|
|
required_files = [
|
|
"models/linkedin_models.py",
|
|
"services/linkedin_service.py",
|
|
"routers/linkedin.py",
|
|
"test_linkedin_endpoints.py"
|
|
]
|
|
|
|
all_exist = True
|
|
for file_path in required_files:
|
|
if not check_file_exists(file_path):
|
|
all_exist = False
|
|
|
|
return all_exist
|
|
|
|
def main():
|
|
"""Run all validations."""
|
|
print("🚀 LinkedIn Content Generation Structure Validation")
|
|
print("=" * 60)
|
|
|
|
results = {}
|
|
|
|
# Validate file structure
|
|
results["file_structure"] = validate_file_structure()
|
|
|
|
# Validate individual components
|
|
results["models"] = validate_linkedin_models()
|
|
results["service"] = validate_linkedin_service()
|
|
results["router"] = validate_linkedin_router()
|
|
|
|
# Summary
|
|
print("\n📊 Validation Results")
|
|
print("=" * 40)
|
|
|
|
passed = sum(results.values())
|
|
total = len(results)
|
|
|
|
for component, result in results.items():
|
|
status = "✅ PASSED" if result else "❌ FAILED"
|
|
print(f"{component}: {status}")
|
|
|
|
print(f"\nOverall: {passed}/{total} validations passed ({(passed/total)*100:.1f}%)")
|
|
|
|
if passed == total:
|
|
print("\n🎉 All structure validations passed!")
|
|
print("The LinkedIn content generation migration is structurally complete.")
|
|
print("\nNext steps:")
|
|
print("1. Install required dependencies (fastapi, pydantic, etc.)")
|
|
print("2. Configure API keys (GEMINI_API_KEY)")
|
|
print("3. Start the FastAPI server")
|
|
print("4. Test the endpoints")
|
|
else:
|
|
print(f"\n⚠️ {total - passed} validation(s) failed. Please review the implementation.")
|
|
|
|
return passed == total
|
|
|
|
if __name__ == "__main__":
|
|
success = main()
|
|
sys.exit(0 if success else 1) |