grantforge-api / backend /simulate_429_autofix.py
GrantForge Bot
Deploy sha-9a5957fcdef15b7e2623f8b147cda6026475aee0 — source build (no GHCR)
3a3734f
Raw
History Blame Contribute Delete
5.05 kB
import sys
import os
import time
import asyncio
from unittest.mock import patch, MagicMock
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from endpoints.projects import autofix_project_section
from fastapi import HTTPException
# Mock klas
class DummyProject:
id = "proj_1"
clerk_user_id = "clerk_123"
title = "Projekt Testowy"
program_type = "SMART"
final_document_audit_result = {
"issues": [
{
"affected_section": "Ogólne",
"severity": "high",
"category": "logic",
"message": "Brak spójności",
"recommendation": "Popraw spójność",
}
]
}
external_context = {}
class DummySection:
id = "sec_1"
project_id = "proj_1"
section_type = "project_summary"
content = "Oryginalna treść sekcji."
class DummyQuery:
def __init__(self, model):
self.model = model
def filter(self, *args, **kwargs):
return self
def join(self, *args, **kwargs):
return self
def first(self):
if hasattr(self.model, "__name__"):
if self.model.__name__ == "Project":
return DummyProject()
elif self.model.__name__ == "ProjectSection":
return DummySection()
return None
def all(self):
return []
class DummyDB:
def query(self, model, *args, **kwargs):
return DummyQuery(model)
def add(self, obj):
pass
def commit(self):
pass
def refresh(self, obj):
pass
def run_simulation():
print("==================================================")
print("[SYMULACJA] BŁĘDÓW 429 (RATE LIMIT) LLM W AUTOFIX")
print("==================================================")
db = DummyDB()
call_count = 0
# Mock dla metody invoke w łańcuchu LangChain
def mock_chain_invoke(*args, **kwargs):
nonlocal call_count
call_count += 1
print(f"\n[LLM Request] Próba nr {call_count}...")
if call_count < 3:
print(
"[LLM Error] Symulowanie bledu: 429 ResourceExhausted (Przekroczono limit Quota)"
)
# Rzucamy wyjątek, który backend normalnie by dostał od Google API
raise Exception("429 ResourceExhausted: Quota exceeded for AI")
print("[LLM Success] Zwracanie poprawnej odpowiedzi na 3. probie!")
mock_response = MagicMock()
mock_response.content = (
"Zaktualizowana i poprawiona treść sekcji z uwzględnieniem audytu."
)
return mock_response
# Ponieważ 'chain' jest tworzony wewnątrz funkcji, zrobimy patch na PromptTemplate.__or__
# albo bezpośrednio na klasie RunnableSequence
with patch("endpoints.projects.get_llm") as mock_get_llm:
# Konstruujemy mockowany LLM
mock_llm = MagicMock()
mock_get_llm.return_value = mock_llm
# Zamiast patchować '|' (or), po prostu zrobimy patch na chain.invoke
# w Pythonie możemy użyć mocka na całej klasie PromptTemplate, ale łatwiej patchować llm
# Mockujemy zachowanie łańcucha prompt | llm
# W Langchain operator | tworzy RunnableSequence. Mockujemy zachowanie invoke na wyniku
with patch(
"endpoints.projects.PromptTemplate.from_template"
) as mock_from_template:
mock_prompt = MagicMock()
mock_from_template.return_value = mock_prompt
mock_chain = MagicMock()
mock_chain.invoke.side_effect = mock_chain_invoke
mock_prompt.__or__.return_value = mock_chain
# Należy też zmockować ProjectSectionVersion
with patch("endpoints.projects.ProjectSectionVersion"):
try:
start_time = time.time()
# Nowa sygnatura funkcji
result = asyncio.run(
autofix_project_section(
project_id="proj_1",
section_id="sec_1",
token_data={"sub": "clerk_123"},
db=db,
)
)
end_time = time.time()
print("\n==================================================")
print("[WYNIK SYMULACJI]")
print("Status: SUKCES (Udało się przetrwać błędy 429!)")
print(
f"Całkowity czas wykonania: {end_time - start_time:.2f} sekund"
)
print(f"Zwrócony tekst:\n{result.content}")
print("==================================================")
except HTTPException as e:
print(
f"\n[Frontend Error] Funkcja rzucila HTTP 429 do Frontendu po wyczerpaniu limitu prob: {e.detail}"
)
if __name__ == "__main__":
run_simulation()