Repository navigation
Index images without OCR text and route vision analysis through its AI connection - #1584
Merged
Paul Lizer (paullizer) merged 4 commits intoSep 30, 2026
Conversation
…I connection Text-free images such as an overexposed photo of an empty lab floor ended with no search chunk even though the vision model described them (microsoft#1583). - Index an image's AI vision description on its own when OCR finds no text, and treat Layout output that is only page-number or page-break annotations (for example <!-- PageNumber="J" -->) as no text. Header and footer text still counts. - Build the stored chunk text, including the vision block, before embedding so save_chunks and save_chunks_batch embed exactly what they store. Never index a failed or empty vision analysis, and never write an empty chunk. - Read string fields, including Summary, from the Content Understanding image analyzer, and fall back to it for standalone images (workspace and chat uploads) when the document analyzer returns nothing, before Document Intelligence Layout. - Resolve the stored vision model name to the enabled AI connection that hosts it with the pure find_enabled_model_endpoint_for_model_name(), share the client construction with metadata extraction, and make Test Vision Analysis use the same connection as ingestion. Refs microsoft#1583 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2024-12-01-preview predates gpt-image support. 2025-04-01-preview is the newest dated Azure OpenAI API version and is documented for gpt-image-1, 1.5, and 2. - Add AZURE_OPENAI_IMAGE_GEN_API_VERSION_DEFAULT and use it as the azure_openai_image_gen_api_version default. - Add normalize_image_generation_api_version_settings(), run on every settings load, to upgrade a stored value that is exactly the previous default (AZURE_OPENAI_IMAGE_GEN_API_VERSION_PREVIOUS_DEFAULT) or blank. Any other value is kept, and azure_apim_image_gen_api_version is never changed. - Update the admin docs default and the example and seeder settings artifacts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Covers the text-free image indexing and vision routing fix (microsoft#1583) and the image generation API version default. Refs microsoft#1583 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Assert the token usage of the no-vision save_chunks_batch case, so the value is read before it is reassigned (py/multiple-definition). - Add a fresh-process probe that imports functions_content_understanding before functions_content and checks the image analyzer fallback, so both import orders are covered for the pre-existing functions_content -> functions_content_understanding -> functions_settings -> functions_document_actions -> functions_search -> functions_content cycle (py/cyclic-import). This PR adds no new module dependency; document the cycle and defer breaking it. Refs microsoft#1583 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
merged commit Sep 30, 2026
be01d94
into
microsoft:Development
12 checks passed
Paul Lizer (paullizer)
added a commit
that referenced
this pull request
Sep 30, 2026
…I connection Folded from the Development fix (#1584) for #1583: - An image whose OCR output is empty, or only a Document Intelligence page-number comment, is indexed from its AI vision description, and chunk embeddings are built from the stored text including the vision block. - Standalone images fall back to the Content Understanding image analyzer, whose Summary field is now read, before Document Intelligence Layout. - The vision model name resolves to the enabled AI connection that hosts it, for ingestion, chat image uploads and the admin vision test. React V2 adjustments: - The shared model-endpoint client helper keeps V2's order: find the model and re-check its chat capability before resolving Key Vault secrets. Metadata extraction behaves as before. - Vision analysis re-checks image support on the resolved connection model, and the legacy path keeps its existing checks. - A page that fits the embedding budget embeds its OCR text when the vision block would push it over, instead of being refused by the non-legacy embedding guard. - The V2 admin help text and the Knowledge docs describe the new behavior. (cherry picked from commit b91f9d5) Refs #1583 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
that referenced
this pull request
Sep 30, 2026
Folded from the Development fix (#1584): the image generation API version defaults to 2025-04-01-preview, the newest dated Azure OpenAI version and the one documented for gpt-image models, and a saved 2024-12-01-preview (the previous default) or blank value is upgraded when settings load. APIM versions are never changed. React V2 adjustments: - Image connection profiles imported with the previous default are upgraded the same way, and APIM profiles are left alone. - Unmigrated legacy Images settings with no version fall back to 2025-04-01-preview. - The V2 admin field default and the AI Models and image generation docs match. (cherry picked from commit 4882390) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #1583
Summary
Text-free images, such as an overexposed photo of an empty lab floor, ended with Processing complete - no text found in image: no title, 0 chunks in AI Search, and nothing chat could use, even though the vision model had described them. This PR indexes the vision description when OCR finds no text, falls back to Content Understanding's image analyzer for standalone images, and calls the vision model on the AI connection that actually hosts it.
It also raises the default Azure OpenAI image generation API version to
2025-04-01-preview(separate section below). One version bump,0.261.047, covers both.Root cause
prebuilt-documentSearchreturned no pages, so extraction fell back to DIprebuilt-layout. Layout read floor tape as the page numberJ(<!-- PageNumber="J" -->) on one photo and returned nothing for the other. The bogus comment became the first photo's only chunk; the second got none, so final metadata extraction was skipped too.save_chunksappended the vision block after embedding the OCR text (embedding - 7 tokens).prebuilt-imageSearchreturnsas markdown and the description infields.Summary.valueString, whichanalyze_image_with_content_understandingignored.analyze_image_with_vision_modelalways used the legacyazure_openai_gpt_*/APIM client, sogpt-5.6-luna(deployed only on another connection) returned 404, while the admin test resolved the real connection and passed.Changes
Index image descriptions when OCR finds no text (
functions_documents.py)_format_vision_analysis_block()replaces the duplicated inline formatting. Valid analyses keep the exact=== AI Vision Analysis ===format; missing, non-dict,error, or empty analyses return''.save_chunks()builds the stored text (OCR + vision block, no leading blank lines when OCR is empty) before embedding and embeds that same text, keeping the last-resort clamp guard. It never writes an empty chunk.save_chunks_batch()uses the same helpers.process_di_document()records whether this run produced a usable vision analysis, keeps only image OCR pages with real text, and otherwise saves one description-only page-1 chunk (flaggedvision_description_only). Final metadata extraction then runs. Images with real OCR text are unchanged; vision still runs only with Enhanced Citations on.Content Understanding image analyzer fallback (
functions_content_understanding.py,functions_content.py,route_frontend_chats.py)analyze_image_with_content_understanding()emitsSummaryas plain text and other string fields asName: value, ignores placeholder-only markdown, and keeps figure summaries. This also fixes images embedded in DOCX/PPTX files analyzed with CU, which were indexed with just theplaceholder.extract_content_with_extraction_engine(..., is_image=False): when the document analyzer returns nothing for an image, the image analyzer's description becomes page 1 with the reason Content Understanding found no text, so its image analyzer description was indexed. If it fails or returns nothing, extraction falls back to DI Layout exactly as before (with a warning). PDFs and other files are unchanged. Workspace uploads threadis_imagefromprocess_di_document; direct chat uploads passis_image=is_image_file.Route the vision model through its AI connection (
functions_model_endpoint_types.py,functions_documents.py,route_backend_settings.py)find_enabled_model_endpoint_for_model_name(endpoints, model_name)→(endpoint, model)or(None, None): enabled endpoints/models only; deployment name or resolved request model first, then model name, then id; first match in endpoint order._build_model_endpoint_client_for_model()now holds the client construction moved out of_resolve_metadata_extraction_client(Key Vault resolution, request model, API version/protocol checks, provider allowlist). Metadata extraction keeps the same behavior, order, and error messages.analyze_image_with_vision_model()uses the matched connection and sendsmodel=<resolved request model>viaresolve_vision_model_endpoint(); otherwise the legacy APIM/direct client is unchanged. It logs the connection by name/id only and still returnsNoneon errors. Chat image uploads benefit automatically._test_multimodal_vision_connection()now resolves the name the same way, so Test Vision Analysis uses the ingestion connection, including when APIM is checked with multi-endpoint models enabled (previously it tested APIM while ingestion would not).Image generation API version default
azure_openai_image_gen_api_versionnow defaults toAZURE_OPENAI_IMAGE_GEN_API_VERSION_DEFAULT = '2025-04-01-preview', the newest dated Azure OpenAI version and the one documented for gpt-image-1, 1.5, and 2.2024-12-01-previewpredates gpt-image support.normalize_image_generation_api_version_settings(), run fromnormalize_loaded_settings(), upgrades a stored value that is exactly the previous default (AZURE_OPENAI_IMAGE_GEN_API_VERSION_PREVIOUS_DEFAULT) or blank. Any other value is kept.azure_apim_image_gen_api_versionis never changed because the gateway defines its version.docs/admin/ai-models.md,artifacts/cosmos_examples/cosmos-settings-example.json, and the database seederadmin_settings.json(image generation entries only).Tests
functional_tests/test_image_description_indexing_without_ocr_text.py(8 tests): pure lookup tests in-process; real modules in fresh normal and-Oprocesses with external I/O blocked, reusing the issue payloads (CUprebuilt-imageSearchresult, empty/PageNumber="J"DI output). Covers vision block formatting, save/embed parity, description-only chunks, header-only OCR kept, CU Summary parsing and fallback, vision connection lookup and legacy fallback, unchanged metadata-extraction client behavior and messages, the admin test agreement, and the chat call site.functional_tests/test_image_generation_api_version_default.py(17 tests): default, migration cases (old default, blank, custom2025-03-01-previewuntouched, APIM untouched), wiring, docs/artifacts, and a realget_settings()load that persists the migration.test_markdown_chunk_size_enforcement.py(4/8),test_vision_model_parameter_fix.py,test_document_auto_metadata_extraction_consistency.py(3/4),test_multiselect_metadata_extraction.py(4/5),test_image_generation_model_compatibility.py(2/4).Notes
PageNumber/PageBreakcomments count as non-text;PageHeader/PageFootercomments carry recognized text and still count, so header- or footer-only images are not dropped.Docs:
docs/explanation/fixes/IMAGE_DESCRIPTION_INDEXING_WITHOUT_OCR_TEXT_FIX.md,docs/explanation/fixes/IMAGE_GENERATION_API_VERSION_DEFAULT_FIX.md, release notes under0.261.047, and updates todocs/admin/knowledge.md,docs/admin/workspaces.md, and the Content Understanding feature doc.