diff --git a/archive-doc-gen/src/backend/settings.py b/archive-doc-gen/src/backend/settings.py index 87c589c86..189f3b716 100644 --- a/archive-doc-gen/src/backend/settings.py +++ b/archive-doc-gen/src/backend/settings.py @@ -266,6 +266,11 @@ class _AzureSearchSettings(BaseSettings, DatasourcePayloadConstructor): extra="ignore", env_ignore_empty=True, ) + + def __init__(self, *args, settings: "_AppSettings", **data): + # Ensure DatasourcePayloadConstructor.__init__ runs so that _settings is initialized + super().__init__(*args, settings=settings, **data) + _type: Literal["azure_search"] = PrivateAttr(default="azure_search") top_k: int = Field(default=5, serialization_alias="top_n_documents") strictness: int = 3 diff --git a/archive-doc-gen/src/frontend/src/components/ChatHistory/ChatHistoryListItem.tsx b/archive-doc-gen/src/frontend/src/components/ChatHistory/ChatHistoryListItem.tsx index b14b50039..d62fdb2b3 100644 --- a/archive-doc-gen/src/frontend/src/components/ChatHistory/ChatHistoryListItem.tsx +++ b/archive-doc-gen/src/frontend/src/components/ChatHistory/ChatHistoryListItem.tsx @@ -7,7 +7,6 @@ import { DialogType, IconButton, ITextField, - ITooltipHostStyles, List, PrimaryButton, Separator, diff --git a/archive-doc-gen/src/frontend/src/components/ChatHistory/chatHistoryListItem.test.tsx b/archive-doc-gen/src/frontend/src/components/ChatHistory/chatHistoryListItem.test.tsx index a7eccb4c9..bacd0734d 100644 --- a/archive-doc-gen/src/frontend/src/components/ChatHistory/chatHistoryListItem.test.tsx +++ b/archive-doc-gen/src/frontend/src/components/ChatHistory/chatHistoryListItem.test.tsx @@ -553,11 +553,10 @@ describe('ChatHistoryListItemCell', () => { }, 10000) test('shows error when trying to rename to an existing title', async () => { - const existingTitle = 'Existing Chat Title' - ; (historyRename as jest.Mock).mockResolvedValueOnce({ - ok: false, - json: async () => ({ message: 'Title already exists' }) - }) + (historyRename as jest.Mock).mockResolvedValueOnce({ + ok: false, + json: async () => ({ message: 'Title already exists' }) + }) renderWithContext(, mockAppState) @@ -570,12 +569,12 @@ describe('ChatHistoryListItemCell', () => { }) const inputItem = screen.getByPlaceholderText(conversation.title) - fireEvent.change(inputItem, { target: { value: 'Test Chat' } }) + fireEvent.change(inputItem, { target: { value: 'Another Existing Chat' } }) fireEvent.keyDown(inputItem, { key: 'Enter', code: 'Enter', charCode: 13 }) await waitFor(() => { - expect(screen.getByText(/Error: Enter a new title to proceed./i)).toBeInTheDocument() + expect(screen.getByText(/Error: could not rename item/i)).toBeInTheDocument() }) }) diff --git a/archive-doc-gen/src/frontend/src/pages/chat/Chat.tsx b/archive-doc-gen/src/frontend/src/pages/chat/Chat.tsx index a13b5b569..3520e075e 100644 --- a/archive-doc-gen/src/frontend/src/pages/chat/Chat.tsx +++ b/archive-doc-gen/src/frontend/src/pages/chat/Chat.tsx @@ -6,9 +6,6 @@ import { Dialog, DialogType, Stack, - IStackTokens, - mergeStyleSets, - IModalStyles, Spinner, SpinnerSize } from '@fluentui/react' diff --git a/archive-doc-gen/tests/e2e-test/pages/draftPage.py b/archive-doc-gen/tests/e2e-test/pages/draftPage.py index 760a54e55..3ddebfd0b 100644 --- a/archive-doc-gen/tests/e2e-test/pages/draftPage.py +++ b/archive-doc-gen/tests/e2e-test/pages/draftPage.py @@ -1,5 +1,4 @@ import time -import os from base.base import BasePage from pytest_check import check from playwright.sync_api import expect diff --git a/archive-doc-gen/tests/e2e-test/tests/test_st_docgen_tc.py b/archive-doc-gen/tests/e2e-test/tests/test_st_docgen_tc.py index de55c599a..172199607 100644 --- a/archive-doc-gen/tests/e2e-test/tests/test_st_docgen_tc.py +++ b/archive-doc-gen/tests/e2e-test/tests/test_st_docgen_tc.py @@ -6,7 +6,7 @@ import pytest from pytest_check import check from playwright.sync_api import expect -from config.constants import (URL, add_section, browse_question1, browse_question2, browse_question3, +from config.constants import (add_section, browse_question1, browse_question2, browse_question3, browse_question4, browse_question5, generate_question1, invalid_response, invalid_response1, remove_section) from pages.browsePage import BrowsePage @@ -538,7 +538,6 @@ def test_show_hide_chat_history(login_logout, request): page = login_logout home_page = HomePage(page) - browse_page = BrowsePage(page) generate_page = GeneratePage(page) log_capture = io.StringIO() @@ -2503,14 +2502,13 @@ def test_bug_7571_removed_sections_not_returning(request, login_logout): logger.info("Step 4: Enter a prompt to remove sections one by one 'Remove (section name)'") start = time.time() - # Select 3 sections to remove from the initial list - sections_to_remove = [] - if initial_count >= 3: - # Remove sections at positions 1, 2, and 3 (avoid removing first section for stability) - indices_to_remove = [1, 2, 3] if initial_count > 3 else list(range(1, initial_count)) - for idx in indices_to_remove: - if idx < len(initial_sections): - sections_to_remove.append(initial_sections[idx]) + # Select up to 3 sections to remove from the initial list (avoid removing first section for stability) + indices_to_remove = [1, 2, 3] if initial_count > 3 else list(range(1, initial_count)) + sections_to_remove = [ + initial_sections[idx] + for idx in indices_to_remove + if idx < len(initial_sections) + ] logger.info("Sections selected for removal: %s", sections_to_remove) @@ -2739,6 +2737,9 @@ def test_bug_9825_navigate_between_sections(request, login_logout): page.wait_for_timeout(1000) + duration = time.time() - start + logger.info("Execution Time for Step 6: %.2fs", duration) + logger.info("\n" + "="*80) logger.info("✅ TC 10157 Test Summary - Navigate between sections") logger.info("="*80) @@ -3398,7 +3399,7 @@ def test_bug_10177_edit_delete_icons_disabled_during_response(login_logout, requ try: threads.first.wait_for(state="visible", timeout=10000) logger.info("✅ Chat history created and displayed with %d thread(s)", threads.count()) - except: + except Exception: logger.error("❌ Chat history threads not visible after creation") # Try alternative locator threads_alt = page.locator('div[data-list-index]') @@ -3448,7 +3449,7 @@ def test_bug_10177_edit_delete_icons_disabled_during_response(login_logout, requ try: delete_icon.wait_for(state="visible", timeout=2000) is_delete_visible = True - except: + except Exception: is_delete_visible = False is_delete_enabled = delete_icon.is_enabled() if is_delete_visible else False @@ -3460,7 +3461,7 @@ def test_bug_10177_edit_delete_icons_disabled_during_response(login_logout, requ try: edit_icon.wait_for(state="visible", timeout=2000) is_edit_visible = True - except: + except Exception: is_edit_visible = False is_edit_enabled = edit_icon.is_enabled() if is_edit_visible else False @@ -3914,7 +3915,9 @@ def test_bug_16106_tooltip_on_chat_history_hover(login_logout, request): with check: assert thread_count > 0, "No chat history threads found to hover over" - if thread_count > 0: + if thread_count <= 0: + logger.warning("Skipping hover action: no chat history threads available.") + else: # Hover over the first chat thread to trigger tooltip first_thread = history_threads.nth(0) first_thread.hover() @@ -3989,8 +3992,6 @@ def test_bug_16106_tooltip_on_chat_history_hover(login_logout, request): if tooltip_found: logger.info("✅ Tooltip displayed successfully on chat history hover") logger.info("Tooltip text length: %d characters", len(tooltip_text)) - else: - logger.error("❌ BUG FOUND: No tooltip displayed when hovering over chat history") duration = time.time() - start logger.info("Execution Time for 'Verify tooltip': %.2fs", duration) @@ -4007,7 +4008,7 @@ def test_bug_16106_tooltip_on_chat_history_hover(login_logout, request): page.keyboard.press("Escape") page.wait_for_timeout(1000) logger.info("Closed chat history using Escape key") - except: + except Exception: logger.warning("Chat history panel may still be open") logger.info("\n%s", "="*80) @@ -4102,10 +4103,10 @@ def test_bug_26031_validate_empty_spaces_chat_input(login_logout, request): assert current_responses_empty == initial_responses, \ f"BUG: System accepted empty query. Response count changed from {initial_responses} to {current_responses_empty}" - if current_responses_empty == initial_responses: - logger.info("✅ System did not accept empty query - no response generated") - else: + if current_responses_empty != initial_responses: logger.error("❌ BUG: System accepted empty query and generated response") + else: + logger.info("✅ System did not accept empty query - no response generated") else: logger.info("✅ Send button is properly disabled for empty input") diff --git a/content-gen/scripts/create_image_search_index.py b/content-gen/scripts/create_image_search_index.py index c67a613e8..2218fecfb 100644 --- a/content-gen/scripts/create_image_search_index.py +++ b/content-gen/scripts/create_image_search_index.py @@ -10,7 +10,6 @@ """ import asyncio -import json import os import sys from pathlib import Path diff --git a/content-gen/scripts/post_deploy.py b/content-gen/scripts/post_deploy.py index 47ace7d6a..12b0d3a75 100644 --- a/content-gen/scripts/post_deploy.py +++ b/content-gen/scripts/post_deploy.py @@ -36,13 +36,11 @@ import argparse import asyncio import base64 -import json import os import sys -import time from dataclasses import dataclass from pathlib import Path -from typing import Optional, List, Dict, Any +from typing import Dict try: import httpx diff --git a/content-gen/scripts/sample_content_generation.py b/content-gen/scripts/sample_content_generation.py index 05b02569c..c2a0e0d98 100644 --- a/content-gen/scripts/sample_content_generation.py +++ b/content-gen/scripts/sample_content_generation.py @@ -28,7 +28,6 @@ import asyncio import argparse import json -import os import sys from datetime import datetime from pathlib import Path @@ -288,7 +287,7 @@ async def main(): # Generate content try: - result = await generate_content_sample( + await generate_content_sample( brief=brief, products=products, generate_images=not args.no_images, diff --git a/content-gen/scripts/test_content_generation.py b/content-gen/scripts/test_content_generation.py index 3896a2465..acbb41a91 100644 --- a/content-gen/scripts/test_content_generation.py +++ b/content-gen/scripts/test_content_generation.py @@ -12,7 +12,6 @@ """ import asyncio -import json import sys import os from typing import Dict, Any diff --git a/content-gen/src/backend/app.py b/content-gen/src/backend/app.py index aecdf7f8d..5174fc34f 100644 --- a/content-gen/src/backend/app.py +++ b/content-gen/src/backend/app.py @@ -676,8 +676,6 @@ async def generate_content(): Returns streaming response with generated content. """ - import asyncio - data = await request.get_json() brief_data = data.get("brief", {}) @@ -876,8 +874,6 @@ async def regenerate_content(): Returns regenerated image with the modification applied. """ - import asyncio - data = await request.get_json() modification_request = data.get("modification_request", "") diff --git a/content-gen/src/backend/orchestrator.py b/content-gen/src/backend/orchestrator.py index 7677ca362..7d9e5be1f 100644 --- a/content-gen/src/backend/orchestrator.py +++ b/content-gen/src/backend/orchestrator.py @@ -1511,8 +1511,13 @@ async def generate_content( try: prompt_data = json.loads(json_match.group(1)) prompt_text = prompt_data.get('prompt', prompt_data.get('image_prompt', prompt_text)) - except: - pass + except Exception as parse_error: + # Best-effort JSON extraction from markdown code block; on failure, + # fall back to the original prompt_text without interrupting image generation. + logger.debug( + "Failed to parse JSON from markdown code block for image prompt: %s", + parse_error, + ) # Build product description for DALL-E context # Include detailed image descriptions if available for better color accuracy @@ -1576,7 +1581,13 @@ async def generate_content( for v in results["violations"] ) except (json.JSONDecodeError, KeyError): - pass + # If the compliance response is not valid JSON or missing expected keys, + # continue without structured violations data but log for observability. + logger.debug( + "Could not parse structured compliance violations from response; " + "proceeding without 'violations' / 'requires_modification'.", + exc_info=True, + ) except Exception as e: logger.exception(f"Error generating content: {e}") @@ -1744,8 +1755,11 @@ async def regenerate_image( prompt_data = json.loads(json_match.group(1)) prompt_text = prompt_data.get('prompt', prompt_text) change_summary = prompt_data.get('change_summary', modification_request) - except: - pass + except Exception as parse_error: + logger.debug( + "Failed to parse JSON from image modification response fallback: %s", + parse_error, + ) results["image_prompt"] = prompt_text results["message"] = f"Regenerating image: {change_summary}" diff --git a/content-gen/src/backend/services/cosmos_service.py b/content-gen/src/backend/services/cosmos_service.py index 11f55400d..caac4bc4d 100644 --- a/content-gen/src/backend/services/cosmos_service.py +++ b/content-gen/src/backend/services/cosmos_service.py @@ -308,8 +308,13 @@ async def get_conversation( max_item_count=1 ): return item - except Exception: - pass + except Exception as exc: + logger.warning( + "Cross-partition conversation lookup failed for id=%s, user_id=%s: %s", + conversation_id, + user_id, + exc, + ) return None diff --git a/content-gen/tests/rai_testing.py b/content-gen/tests/rai_testing.py index 78a8fcc30..996131730 100644 --- a/content-gen/tests/rai_testing.py +++ b/content-gen/tests/rai_testing.py @@ -26,11 +26,9 @@ import argparse import asyncio import json -import os -import subprocess import sys import time -from dataclasses import dataclass, asdict +from dataclasses import dataclass from datetime import datetime from enum import Enum from pathlib import Path @@ -41,9 +39,17 @@ # Try to import Azure Identity for auth try: from azure.identity import AzureCliCredential, InteractiveBrowserCredential - AZURE_IDENTITY_AVAILABLE = True except ImportError: - AZURE_IDENTITY_AVAILABLE = False + # Azure Identity is optional; provide stubs that fail clearly if Azure auth is requested. + class _MissingAzureIdentityCredential: + def __init__(self, *args, **kwargs) -> None: + raise RuntimeError( + "The 'azure-identity' package is required to use '--use-azure-auth'. " + "Install it with 'pip install azure-identity' and try again." + ) + + AzureCliCredential = _MissingAzureIdentityCredential + InteractiveBrowserCredential = _MissingAzureIdentityCredential class TestCategory(Enum): @@ -966,7 +972,7 @@ async def main(): # Generate report report_path = runner.generate_report(args.output_dir) - print(f"\nReports saved to: {args.output_dir}") + print(f"\nReports saved to: {report_path}") return runner.print_summary() diff --git a/content-gen/tests/test_agents.py b/content-gen/tests/test_agents.py index feb7ae7e3..dccbdf667 100644 --- a/content-gen/tests/test_agents.py +++ b/content-gen/tests/test_agents.py @@ -2,10 +2,7 @@ Unit tests for the Content Generation agents. """ -import pytest -from unittest.mock import AsyncMock, MagicMock, patch - -from backend.models import CreativeBrief, Product, ComplianceSeverity +from backend.models import CreativeBrief, Product from backend.agents.text_content_agent import validate_text_compliance from backend.agents.compliance_agent import comprehensive_compliance_check diff --git a/docs/generate_architecture.py b/docs/generate_architecture.py index d6c680c12..ca86d588d 100644 --- a/docs/generate_architecture.py +++ b/docs/generate_architecture.py @@ -15,7 +15,7 @@ from diagrams.azure.compute import ContainerInstances, AppServices, ContainerRegistries from diagrams.azure.database import CosmosDb, BlobStorage from diagrams.azure.ml import CognitiveServices -from diagrams.azure.network import VirtualNetworks, PrivateEndpoint, DNSZones +from diagrams.azure.network import PrivateEndpoint from diagrams.azure.analytics import AnalysisServices from diagrams.onprem.client import User diff --git a/docs/generate_architecture_png.py b/docs/generate_architecture_png.py index 0f441e1b9..6a684cddd 100644 --- a/docs/generate_architecture_png.py +++ b/docs/generate_architecture_png.py @@ -19,7 +19,6 @@ def draw_rounded_rect(draw, xy, radius, fill=None, outline=None, width=1): """Draw a rounded rectangle""" - x1, y1, x2, y2 = xy draw.rounded_rectangle(xy, radius=radius, fill=fill, outline=outline, width=width) def draw_service_box(draw, x, y, w, h, title, subtitle="", icon_type="default", highlight=False): @@ -69,7 +68,7 @@ def draw_service_box(draw, x, y, w, h, title, subtitle="", icon_type="default", try: font_title = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 13) font_sub = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 10) - except: + except Exception: font_title = ImageFont.load_default() font_sub = ImageFont.load_default() @@ -113,7 +112,7 @@ def main(): try: font_title = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 28) font_label = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 9) - except: + except OSError: font_title = ImageFont.load_default() font_label = ImageFont.load_default() @@ -134,9 +133,7 @@ def main(): COL1_X = 100 COL2_X = 340 - COL3_X = 580 COL4_X = 820 - COL5_X = 1100 # === ROW 1: Frontend Tier === # Container Registry @@ -211,7 +208,7 @@ def main(): # Copyright try: font_copy = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 10) - except: + except Exception: font_copy = ImageFont.load_default() draw.text((50, HEIGHT-30), "© 2024 Microsoft Corporation All rights reserved.", fill=TEXT_GRAY, font=font_copy)