From 3ffe489e32ec50cccd2e60424fb86154109ef66d Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:00:37 +0000 Subject: [PATCH] test --- AI-Document-Generator-main/backend/app.py | 15 ++++++- AI-Document-Generator-main/backend/config.py | 3 ++ .../frontend/src/App.tsx | 17 +++++++- .../frontend/src/hooks/useDocumentWorkflow.ts | 42 ++++++++++++++++--- .../controller/api/ai/AiCreateController.java | 7 ++++ .../api/ai/AiCreateInternalController.java | 4 ++ docker/compose/docker-compose-ai-stack.yml | 1 + 7 files changed, 82 insertions(+), 7 deletions(-) diff --git a/AI-Document-Generator-main/backend/app.py b/AI-Document-Generator-main/backend/app.py index ec4d1c2965..d371426c79 100644 --- a/AI-Document-Generator-main/backend/app.py +++ b/AI-Document-Generator-main/backend/app.py @@ -72,6 +72,11 @@ def log_job_request_sequence() -> None: def _json_body() -> Dict[str, Any]: return request.get_json(silent=True) or {} +def _require_ai_enabled() -> Optional[Any]: + if CLIENT_MODE != "langchain": + return jsonify({"error": "AI is disabled. Set OPENAI_API_KEY to enable AI features."}), 503 + return None + def _java_url(path: str) -> str: base = JAVA_BACKEND_URL.rstrip("/") @@ -612,6 +617,9 @@ def generate_stream() -> Any: @app.route("/api/create/sessions//stream", methods=["GET"]) def create_stream(session_id: str) -> Any: + disabled = _require_ai_enabled() + if disabled: + return disabled phase = (request.args.get("phase") or "outline").strip().lower() try: session = _fetch_ai_session(session_id) @@ -749,9 +757,14 @@ def create_stream(session_id: str) -> Any: @app.route("/api/create/sessions//fields", methods=["POST"]) def fill_fields(session_id: str) -> Any: + disabled = _require_ai_enabled() + if disabled: + return disabled try: + logger.info("[AI create] fill_fields session_id=%s", session_id) session = _fetch_ai_session(session_id) - except Exception: # noqa: BLE001 + except Exception as exc: # noqa: BLE001 + logger.warning("[AI create] fill_fields session lookup failed session_id=%s error=%s", session_id, exc) return jsonify({"error": "Session not found"}), 404 data = _json_body() diff --git a/AI-Document-Generator-main/backend/config.py b/AI-Document-Generator-main/backend/config.py index b8486cca07..e57fcda943 100644 --- a/AI-Document-Generator-main/backend/config.py +++ b/AI-Document-Generator-main/backend/config.py @@ -23,6 +23,9 @@ os.makedirs(TEMPLATE_DIR, exist_ok=True) OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY") OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL") JAVA_BACKEND_URL = os.environ.get("JAVA_BACKEND_URL", "http://localhost:8080") + +if not OPENAI_API_KEY: + raise RuntimeError("OPENAI_API_KEY is required to start the AI backend.") # Default to GPT-5.1 for full document generation (smart model). # Allow override via SMART_MODEL or legacy OPENAI_MODEL. SMART_MODEL = os.environ.get("SMART_MODEL") or os.environ.get("OPENAI_MODEL") or "gpt-5.1" diff --git a/AI-Document-Generator-main/frontend/src/App.tsx b/AI-Document-Generator-main/frontend/src/App.tsx index 89c9dd6c16..0ff15760e6 100644 --- a/AI-Document-Generator-main/frontend/src/App.tsx +++ b/AI-Document-Generator-main/frontend/src/App.tsx @@ -103,7 +103,22 @@ function App() { setStyleDraft={workflow.setStyleDraft} applyStyleAndRegenerate={workflow.applyStyleAndRegenerate} onAddPromptInfo={workflow.addPromptForFields} - onStageSelect={(nextStage) => workflow.setStage(nextStage)} + onStageSelect={(nextStage) => { + if (workflow.isGenerating || workflow.isStageLoading) return + if (nextStage === 'text' && workflow.stage === 'outline') { + workflow.approveOutline() + return + } + if (nextStage === 'styling' && workflow.stage === 'text') { + workflow.approveDraft() + return + } + if (nextStage === 'review' && workflow.stage === 'styling') { + workflow.saveAndReview() + return + } + workflow.setStage(nextStage) + }} imagePlaceholdersCount={workflow.imagePlaceholdersCount} isAssetUploading={workflow.isAssetUploading} assetError={workflow.assetError} diff --git a/AI-Document-Generator-main/frontend/src/hooks/useDocumentWorkflow.ts b/AI-Document-Generator-main/frontend/src/hooks/useDocumentWorkflow.ts index a34129e0e4..c9b44220d6 100644 --- a/AI-Document-Generator-main/frontend/src/hooks/useDocumentWorkflow.ts +++ b/AI-Document-Generator-main/frontend/src/hooks/useDocumentWorkflow.ts @@ -900,6 +900,11 @@ export function useDocumentWorkflow() { const fillFieldsFromAI = useCallback(async (extraPrompt?: string) => { if (!_aiSessionId) return + console.debug('[AI create] fillFieldsFromAI start', { + sessionId: _aiSessionId, + hasExtraPrompt: Boolean(extraPrompt?.trim()), + outlineCount: outlineRows.length, + }) setIsStageLoading(true) try { const res = await fetch(`/api/v1/ai/create/sessions/${_aiSessionId}/fields`, { @@ -914,6 +919,19 @@ export function useDocumentWorkflow() { }), }) const data = await res.json().catch(() => ({})) + if (!res.ok) { + if (res.status === 503) { + addMessage('assistant', data.error || 'AI is disabled. Set an API key to enable AI features.') + autoFilledRef.current = true + autoFillAttemptsRef.current = 0 + return + } + console.warn('[AI create] fillFieldsFromAI failed', { + sessionId: _aiSessionId, + status: res.status, + data, + }) + } if (!res.ok) { throw new Error(data.error || 'Failed to auto-fill fields') } @@ -950,7 +968,7 @@ export function useDocumentWorkflow() { } finally { setIsStageLoading(false) } - }, [_aiSessionId, outlineRows, autoFillFieldsFromPrompt, prompt, stage, view]) + }, [_aiSessionId, outlineRows, autoFillFieldsFromPrompt, prompt, stage, view, addMessage]) const addPromptForFields = useCallback( (extraPrompt: string) => { @@ -1085,15 +1103,19 @@ export function useDocumentWorkflow() { setIsGenerating(true) setIsLivePreviewing(true) try { - await fetch(`/api/v1/ai/create/sessions/${_aiSessionId}/outline`, { + const res = await fetch(`/api/v1/ai/create/sessions/${_aiSessionId}/outline`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ outlineText, constraints: outlineConstraints }), }) + if (!res.ok) { + const data = await res.json().catch(() => ({})) + throw new Error(data.error || 'Failed to approve outline') + } await runDraft(_aiSessionId) } catch (error) { console.error('Outline approval failed:', error) - addMessage('assistant', 'Failed to approve outline. Please try again.') + addMessage('assistant', error instanceof Error ? error.message : 'Failed to approve outline. Please try again.') } finally { setIsGenerating(false) setIsLivePreviewing(false) @@ -1116,16 +1138,20 @@ export function useDocumentWorkflow() { setIsGenerating(true) setIsLivePreviewing(true) try { - await fetch(`/api/v1/ai/create/sessions/${_aiSessionId}/draft`, { + const res = await fetch(`/api/v1/ai/create/sessions/${_aiSessionId}/draft`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ draftSections }), }) + if (!res.ok) { + const data = await res.json().catch(() => ({})) + throw new Error(data.error || 'Failed to approve draft') + } setStage('styling') await runPolish(_aiSessionId) } catch (error) { console.error('Draft approval failed:', error) - addMessage('assistant', 'Failed to approve draft. Please try again.') + addMessage('assistant', error instanceof Error ? error.message : 'Failed to approve draft. Please try again.') } finally { setIsGenerating(false) setIsLivePreviewing(false) @@ -1229,6 +1255,12 @@ export function useDocumentWorkflow() { }) const createData = await createResponse.json().catch(() => ({})) + console.debug('[AI create] create session response', { + status: createResponse.status, + ok: createResponse.ok, + sessionId: createData.sessionId, + error: createData.error, + }) if (!createResponse.ok || !createData.sessionId) { throw new Error(createData.error || 'Failed to create AI session') } diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateController.java b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateController.java index ec6df23825..b8604adeb8 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateController.java @@ -49,6 +49,12 @@ public class AiCreateController { } AiCreateSession session = sessionService.createSession(request.prompt(), request.docType(), request.templateId()); + log.info( + "AI create session created sessionId={} userId={} docType={} templateId={}", + session.getSessionId(), + session.getUserId(), + session.getDocType(), + session.getTemplateId()); return ResponseEntity.ok(new CreateSessionResponse(session.getSessionId())); } @@ -122,6 +128,7 @@ public class AiCreateController { public ResponseEntity fillFields( @PathVariable String sessionId, HttpServletRequest request) { sessionService.getSessionForCurrentUser(sessionId); + log.info("AI create fillFields sessionId={}", sessionId); return proxy("POST", "/api/create/sessions/" + sessionId + "/fields", request, false); } diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateInternalController.java b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateInternalController.java index 72b442eeb9..bb4a062063 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateInternalController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ai/AiCreateInternalController.java @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import stirling.software.proprietary.model.ai.AiCreateSession; import stirling.software.proprietary.model.ai.AiCreateSessionStatus; @@ -17,6 +18,7 @@ import stirling.software.proprietary.service.ai.AiCreateSessionService; @RestController @RequestMapping("/api/v1/ai/create/internal") @RequiredArgsConstructor +@Slf4j public class AiCreateInternalController { private final AiCreateSessionService sessionService; @@ -24,6 +26,7 @@ public class AiCreateInternalController { @GetMapping("/sessions/{sessionId}") public ResponseEntity getSession( @PathVariable String sessionId) { + log.info("AI create internal getSession sessionId={}", sessionId); AiCreateSession session = sessionService.getSession(sessionId); return ResponseEntity.ok(AiCreateController.AiCreateSessionResponse.from(session)); } @@ -31,6 +34,7 @@ public class AiCreateInternalController { @PostMapping("/sessions/{sessionId}/update") public ResponseEntity updateSession( @PathVariable String sessionId, @RequestBody UpdateSessionRequest request) { + log.info("AI create internal updateSession sessionId={}", sessionId); AiCreateSession session = sessionService.applyInternalUpdate( sessionId, diff --git a/docker/compose/docker-compose-ai-stack.yml b/docker/compose/docker-compose-ai-stack.yml index 7541119e0b..24f126f588 100644 --- a/docker/compose/docker-compose-ai-stack.yml +++ b/docker/compose/docker-compose-ai-stack.yml @@ -35,6 +35,7 @@ services: - OPENAI_API_KEY=sk-proj-mVg... etc please insert - SMART_MODEL=gpt-5.1 - FAST_MODEL=gpt-4.1-nano + - JAVA_BACKEND_URL=http://backend:8080 networks: - ai-stack