fix: Bing Image Search - Support to override endpoint url (#1025)

The Bing Search resource is undergoing a transition from a Cognitive Service to the Azure Marketplace. During this transition it is possible to have bing search resources that use different endpoint urls.

This fix introduces a new endpoint textbox that defaults to the new default resource url (https://api.bing.microsoft.com/). However, for users with older resources that have not specified the field it will fall back to the older cognitive services url ( https://api.cognitive.microsoft.com/bing).

In addition to the fix this also introduces addition filter options to filter image responses by image size and license type.
Esse commit está contido em:
Wallace Breza
2020-11-04 15:16:36 -08:00
commit de GitHub
commit 27ce840067
10 arquivos alterados com 457 adições e 70 exclusões
+46 -7
Ver Arquivo
@@ -198,15 +198,54 @@ export const english: IAppStrings = {
},
bing: {
title: "Bing Image Search",
options: "Bing Image Search Options",
apiKey: "API Key",
query: "Query",
options: {
title: "Bing Image Search Options",
},
endpoint: {
title: "Endpoint",
description: "The endpoint listed within the Bing Search Azure resource",
},
apiKey: {
title: "API Key",
description: "An API key listed within the Bing Search Azure resource",
},
query: {
title: "Query",
description: "The search query used to populate your connection",
},
aspectRatio: {
title: "Aspect Ratio",
all: "All",
square: "Square",
wide: "Wide",
tall: "Tall",
description: "Filters the results by the specified aspect ratio",
options: {
all: "All",
square: "Square",
wide: "Wide",
tall: "Tall",
},
},
licenseType: {
title: "License Type",
description: "Filters the results by the specified license type",
options: {
all: "All (does not filter any images)",
any: "Any images with any license type",
public: "Public domain",
share: "Free to share and use",
shareCommercially: "Free to share and use commercially",
modify: "Free to modify, share and use",
modifyCommercially: "Free to modify, share and use commercially",
},
},
size: {
title: "Size",
description: "Filters the results by the specified size",
options: {
all: "All",
small: "Small (Less than 200x200)",
medium: "Medium (Less than 500x500)",
large: "Large (Greater than 500x500)",
wallpaper: "Wallpaper (Extra large images)",
},
},
},
local: {
+46 -7
Ver Arquivo
@@ -200,15 +200,54 @@ export const spanish: IAppStrings = {
},
bing: {
title: "Búsqueda de Imágenes Bing",
options: "Opciones de Búsqueda de Imágenes Bing",
apiKey: "Clave API",
query: "Consulta",
options: {
title: "Opciones de Búsqueda de Imágenes Bing",
},
endpoint: {
title: "Extremo",
description: "El punto de conexión que aparece en el recurso de Bing Search Azure",
},
apiKey: {
title: "Clave API",
description: "Una clave de API que aparece en el recurso de Bing Search Azure",
},
query: {
title: "Consulta",
description: "La consulta de búsqueda utilizada para rellenar la conexión",
},
aspectRatio: {
title: "Relación de Aspecto",
all: "Todos",
square: "Cuadrado",
wide: "Ancho",
tall: "Alto",
description: "Filtra los resultados por la relación de aspecto especificada",
options: {
all: "Todos",
square: "Cuadrado",
wide: "Ancho",
tall: "Alto",
},
},
licenseType: {
title: "Tipo de licencia",
description: "Filtra los resultados según el tipo de licencia especificado",
options: {
all: "Todos (no filtra ninguna imagen)",
any: "Cualquier imagen con cualquier tipo de licencia",
public: "Dominio público",
share: "Libre para compartir y usar",
shareCommercially: "Libre para compartir y usar comercialmente",
modify: "Libre de modificar, compartir y usar",
modifyCommercially: "Libre de modificar, compartir y ues comercialmente",
},
},
size: {
title: "Tamaño",
description: "Filtra los resultados según el tamaño especificado",
options: {
all: "Todo",
small: "Pequeño (Menos de 200x200)",
medium: "Medio (Menos de 500x500)",
large: "Grande (mayor de 500x500)",
wallpaper: "Fondo de pantalla (imágenes extra grandes)",
},
},
},
local: {
+46 -7
Ver Arquivo
@@ -205,15 +205,54 @@ export const japanese: IAppStrings = {
},
bing: {
title: "Bing 画像検索", // Bing Image Search,
options: "Bing 画像検索のオプション", // Bing Image Search Options,
apiKey: "APIキー", // API Key,
query: "クエリ", // Query,
options: {
title: "Bing 画像検索のオプション",
}, // Bing Image Search Options,
endpoint: {
title: "エンドポイント", // Endpoint
description: "Bing検索 Azure リソース内に一覧表示されるエンドポイント",
},
apiKey: {
title: "APIキー", // API Key
description: "Bing検索 Azure リソース内に表示される API キー",
},
query: {
title: "クエリ", // Query
description: "接続の設定に使用する検索クエリ",
},
aspectRatio: {
title: "アスペクト比", // Aspect Ratio,
all: "すべて", // All,
square: "正方形", // Square,
wide: "横長", // Wide,
tall: "縦長", // Tall"
description: "指定した縦横比で結果をフィルター処理します。",
options: {
all: "すべて", // All,
square: "正方形", // Square,
wide: "横長", // Wide,
tall: "縦長", // Tall"
},
},
licenseType: {
title: "ライセンスの種類",
description: "指定したライセンスの種類で結果をフィルター処理します。",
options: {
all: "すべて (画像をフィルター処理しません)",
any: "任意のライセンスタイプの画像",
public: "パブリック ドメイン",
share: "無料で共有・使用",
shareCommercially: "無料で共有し、商業的に使用する",
modify: "変更、共有、使用が無料",
modifyCommercially: "無料で変更、共有、および商用で使用",
},
},
size: {
title: "サイズ",
description: "結果を指定したサイズでフィルター処理します。",
options: {
all: "すべての",
small: "小 (200x200 未満)",
medium: "中 (500x500 未満)",
large: "大 (500x500 より大きい)",
wallpaper: "壁紙(特大画像)",
},
},
},
local: {
+48 -9
Ver Arquivo
@@ -173,11 +173,11 @@ export const korean: IAppStrings = {
deleteSuccess: "${connection.name}을 삭제했습니다.", // Successfully deleted ${connection.name}"
},
imageCorsWarning: "경고 : 웹 브라우저에서 VoTT를 사용하는 경우 CORS (Cross Origin Resource Sharing) " +
"제한으로 인해 Bing Image Search의 일부 정보가 제대로 내보내지지 않을 수 있습니다.",
"제한으로 인해 Bing Image Search의 일부 정보가 제대로 내보내지지 않을 수 있습니다.",
// Warning: When using VoTT in a Web browser, some assets from Bing Image Search may no export
// correctly due to CORS (Cross Origin Resource Sharing) restrictions.",
blobCorsWarning: "경고 : 소스 또는 대상 연결로 사용하려면, Azure Blob Storage 계정에서 CORS(Cross Domain Resource Sharing) " +
"설정을 활성화 해야 합니다. CORS 설정에 대한 자세한 정보는 {0}에서 찾을 수 있습니다.",
"설정을 활성화 해야 합니다. CORS 설정에 대한 자세한 정보는 {0}에서 찾을 수 있습니다.",
// Warning: CORS (Cross Domain Resource Sharing) must be enabled on the Azure Blob Storage account, in order
// to use i as a source or target connection. More information on enabling CORS can be found in the {0}",
azDocLinkText: "Azure 설명서.", // Azure Documentation.,
@@ -206,15 +206,54 @@ export const korean: IAppStrings = {
},
bing: {
title: "Bing 이미지 검색", // Bing Image Search,
options: "Bing 이미지 검색 옵션", // Bing Image Search Options,
apiKey: "API 키", // API Key,
query: "쿼리", // Query,
options: {
title: "Bing 이미지 검색 옵션",
}, // Bing Image Search Options,
endpoint: {
title: "끝점",
description: "Bing 검색 Azure 리소스 내에 나열된 끝점",
},
apiKey: {
title: "API 키",
description: "Bing 검색 Azure 리소스 내에 나열된 API 키",
}, // API Key,
query: {
title: "쿼리",
description: "연결을 채우는 데 사용되는 검색 쿼리",
}, // Query,
aspectRatio: {
title: "종횡비", // Aspect Ratio,
all: "모두", // All,
square: "정사각형", // Square,
wide: "넓은", // Wide,
tall: "", // Tall"
description: "지정된 종횡비로 결과를 필터링합니다.",
options: {
all: "모두", // All,
square: "정사각형", // Square,
wide: "넓은", // Wide,
tall: "긴", // Tall"
},
},
licenseType: {
title: "라이센스 유형",
description: "지정된 라이센스 유형으로 결과 필터링",
options: {
all: "모든 (이미지를 필터링하지 않음)",
any: "라이센스 유형이 있는 모든 이미지",
public: "퍼블릭 도메인",
share: "무료 공유 및 사용",
shareCommercially: "상업적으로 자유롭게 공유하고 사용할 수 있습니다.",
modify: "자유롭게 수정, 공유 및 사용",
modifyCommercially: "상업적으로 자유롭게 수정, 공유 및 사용",
},
},
size: {
title: "크기",
description: "지정된 크기로 결과를 필터링합니다.",
options: {
all: "모든",
small: "스몰(200x200 미만)",
medium: "중간(500x500 미만)",
large: "대형(500x500 이상)",
wallpaper: "배경 화면 (초대형 이미지)",
},
},
},
local: {
+46 -7
Ver Arquivo
@@ -205,15 +205,54 @@ export const chinese: IAppStrings = {
},
bing: {
title: "必应图片搜索", // Bing Image Search
options: "必应图像搜索选项", // Bing Image Search Options
apiKey: "API密钥", // API Key
query: "查询", // Query
options: {
title: "必应图像搜索选项",
}, // Bing Image Search Options
endpoint: {
title: "端点",
description: "必应搜索 Azure 资源中列出的终结点",
},
apiKey: {
title: "API密钥",
description: "必应搜索 Azure 资源中列出的 API 密钥",
}, // API Key
query: {
title: "查询",
description: "用于填充连接的搜索查询",
}, // Query
aspectRatio: {
title: "长宽比", // Aspect Ratio
all: "所有", // All
square: "正方形", // Square
wide: "", // Wide
tall: "", // Tall
description: "按指定的纵横比筛选结果",
options: {
all: "所有", // All
square: "正方形", // Square
wide: "宽", // Wide
tall: "高", // Tall
},
},
licenseType: {
title: "许可证类型",
description: "按指定的许可证类型筛选结果",
options: {
all: "全部(不过滤任何图像)",
any: "任何许可证类型的图像",
public: "公有领域",
share: "免费分享和使用",
shareCommercially: "免费共享和使用商业",
modify: "免费修改、共享和使用",
modifyCommercially: "可自由修改、共享和在商业上使用",
},
},
size: {
title: "大小",
description: "按指定大小筛选结果",
options: {
all: "所有",
small: "小(小于200x200",
medium: "中等(小于 500x500",
large: "大(大于 500x500",
wallpaper: "壁纸(超大图像)",
},
},
},
local: {
+46 -7
Ver Arquivo
@@ -208,15 +208,54 @@ export const chinesetw: IAppStrings = {
},
bing: {
title: "Bing 影像搜尋", // Bing Image Search
options: "Bing 影像搜尋選項", // Bing Image Search Options
apiKey: "API密鑰", // API Key
query: "查詢", // Query
options: {
title: "Bing 影像搜尋選項",
}, // Bing Image Search Options
endpoint: {
title: "Endpoint",
description: "必應搜索 Azure 資源中列出的終結點",
},
apiKey: {
title: "API密鑰",
description: "必應搜索 Azure 資源中列出的 API 金鑰",
}, // API Key
query: {
title: "查詢",
description: "用於填充連接的搜索查詢",
}, // Query
aspectRatio: {
title: "長寬比", // Aspect Ratio
all: "所有", // All
square: "矩形", // Square
wide: "", // Wide
tall: "", // Tall
description: "按指定的縱橫比篩選結果",
options: {
all: "所有", // All
square: "矩形", // Square
wide: "寬", // Wide
tall: "高", // Tall
},
},
licenseType: {
title: "許可證類型",
description: "按指定的許可證類型篩選結果",
options: {
all: "全部(不過濾任何影像)",
any: "任何許可證類型的圖像",
public: "公有領域",
share: "免費分享和使用",
shareCommercially: "免費共用和使用商業",
modify: "免費修改、共用和使用",
modifyCommercially: "可自由修改、共用和在商業上使用",
},
},
size: {
title: "大小",
description: "按指定大小篩選結果",
options: {
all: "所有",
small: "小(小於200x200)",
medium: "中等(小於 500x500)",
large: "大(大於 500x500)",
wallpaper: "桌布(超大影像)",
},
},
},
local: {
+49 -10
Ver Arquivo
@@ -200,17 +200,56 @@ export interface IAppStrings {
}
},
bing: {
title: string;
options: string;
apiKey: string;
query: string;
title: string,
endpoint: {
title: string,
description?: string,
},
apiKey: {
title: string,
description?: string,
},
query: {
title: string,
description?: string,
},
options: {
title: string,
},
aspectRatio: {
title: string;
all: string;
square: string;
wide: string;
tall: string;
}
description?: string,
options: {
all: string;
square: string;
wide: string;
tall: string;
}
},
size: {
title: string,
description?: string,
options: {
all: string,
small: string,
medium: string,
large: string,
wallpaper: string,
},
},
licenseType: {
title: string,
description?: string,
options: {
all: string,
any: string,
public: string,
share: string,
shareCommercially: string,
modify: string,
modifyCommercially: string,
},
},
},
local: {
title: string;
@@ -460,7 +499,7 @@ interface IErrorMetadata {
interface IStrings extends LocalizedStringsMethods, IAppStrings { }
export const strings: IStrings = new LocalizedStrings({
// TODO: Need to comment out other languages which will not be used
// TODO: Need to comment out other languages which will not be used
en: english,
es: spanish,
ja: japanese,
+62 -8
Ver Arquivo
@@ -1,19 +1,29 @@
{
"type": "object",
"title": "${strings.connections.providers.bing.options}",
"title": "${strings.connections.providers.bing.options.title}",
"required": ["apiKey","query"],
"properties": {
"endpoint": {
"type": "string",
"title": "Endpoint",
"description": "The endpoint from your Bing Search Azure resource",
"default": "https://api.bing.microsoft.com/",
"pattern": "^https?\\\\://[a-zA-Z0-9\\\\-\\\\.]+\\\\.[a-zA-Z]{2,3}(/\\\\S*)?$"
},
"apiKey": {
"type": "string",
"title": "${strings.connections.providers.bing.apiKey}"
"title": "${strings.connections.providers.bing.apiKey.title}",
"description": "${strings.connections.providers.bing.apiKey.description}"
},
"query": {
"type": "string",
"title": "${strings.connections.providers.bing.query}"
"title": "${strings.connections.providers.bing.query.title}",
"description": "${strings.connections.providers.bing.query.description}"
},
"aspectRatio": {
"type": "string",
"title": "${strings.connections.providers.bing.aspectRatio.title}",
"description": "${strings.connections.providers.bing.aspectRatio.description}",
"enum": [
"all",
"square",
@@ -22,11 +32,55 @@
],
"default": "all",
"enumNames": [
"${strings.connections.providers.bing.aspectRatio.all}",
"${strings.connections.providers.bing.aspectRatio.square}",
"${strings.connections.providers.bing.aspectRatio.wide}",
"${strings.connections.providers.bing.aspectRatio.tall}"
"${strings.connections.providers.bing.aspectRatio.options.all}",
"${strings.connections.providers.bing.aspectRatio.options.square}",
"${strings.connections.providers.bing.aspectRatio.options.wide}",
"${strings.connections.providers.bing.aspectRatio.options.tall}"
]
},
"size": {
"type": "string",
"title": "${strings.connections.providers.bing.size.title}",
"description": "${strings.connections.providers.bing.size.description}",
"enum": [
"All",
"Small",
"Medium",
"Large",
"Wallpaper"
],
"default": "All",
"enumNames": [
"${strings.connections.providers.bing.size.options.all}",
"${strings.connections.providers.bing.size.options.small}",
"${strings.connections.providers.bing.size.options.medium}",
"${strings.connections.providers.bing.size.options.large}",
"${strings.connections.providers.bing.size.options.wallpaper}"
]
},
"licenseType": {
"type": "string",
"title": "${strings.connections.providers.bing.licenseType.title}",
"description": "${strings.connections.providers.bing.licenseType.description}",
"enum": [
"All",
"Any",
"Public",
"Share",
"ShareCommercially",
"Modify",
"ModifyCommercially"
],
"default": "All",
"enumNames": [
"${strings.connections.providers.bing.licenseType.options.all}",
"${strings.connections.providers.bing.licenseType.options.any}",
"${strings.connections.providers.bing.licenseType.options.public}",
"${strings.connections.providers.bing.licenseType.options.share}",
"${strings.connections.providers.bing.licenseType.options.shareCommercially}",
"${strings.connections.providers.bing.licenseType.options.modify}",
"${strings.connections.providers.bing.licenseType.options.modifyCommercially}"
]
}
}
}
}
+40 -5
Ver Arquivo
@@ -1,15 +1,22 @@
import axios from "axios";
import { BingImageSearch, IBingImageSearchOptions, BingImageSearchAspectRatio } from "./bingImageSearch";
import {
BingImageSearch,
IBingImageSearchOptions,
BingImageSearchAspectRatio,
BingImageSearchSize,
BingImageSearchLicenseType,
} from "./bingImageSearch";
import { IAsset, AssetType, AssetState } from "../../models/applicationState";
import MD5 from "md5.js";
describe("Bing Image Search", () => {
const options: IBingImageSearchOptions = {
const defaultOptions: IBingImageSearchOptions = {
apiKey: "ABC123",
query: "Waterfalls",
aspectRatio: BingImageSearchAspectRatio.All,
size: BingImageSearchSize.All,
licenseType: BingImageSearchLicenseType.All,
};
const provider = new BingImageSearch(options);
const assets = [
{ contentUrl: "http://images.com/image1.jpg" },
@@ -26,9 +33,36 @@ describe("Bing Image Search", () => {
});
});
it("calls the Bing image search API", async () => {
it("calls the Bing image search API with default API url", async () => {
const provider = new BingImageSearch(defaultOptions);
// tslint:disable-next-line:max-line-length
const expectedUrl = `https://api.cognitive.microsoft.com/bing/v7.0/images/search?q=${options.query}&aspect=${options.aspectRatio}`;
const expectedUrl = `${BingImageSearch.DefaultApiUrl}/v7.0/images/search?q=${defaultOptions.query}&aspect=${defaultOptions.aspectRatio}&license=${defaultOptions.licenseType}&size=${defaultOptions.size}`;
const expectedHeaders = {
headers: {
"Ocp-Apim-Subscription-Key": defaultOptions.apiKey,
"Accept": "application/json",
},
};
await provider.getAssets();
expect(axios.get).toBeCalledWith(expectedUrl, expectedHeaders);
});
it("calls the Bing image search API with custom configuration", async () => {
const options: IBingImageSearchOptions = {
...defaultOptions,
apiKey: "XYZ123",
query: "Custom",
endpoint: "https://api.bing.microsoft.com",
aspectRatio: BingImageSearchAspectRatio.Square,
licenseType: BingImageSearchLicenseType.Public,
size: BingImageSearchSize.Large,
};
const provider = new BingImageSearch(options);
// tslint:disable-next-line:max-line-length
const expectedUrl = `${options.endpoint}/v7.0/images/search?q=${options.query}&aspect=${options.aspectRatio}&license=${options.licenseType}&size=${options.size}`;
const expectedHeaders = {
headers: {
"Ocp-Apim-Subscription-Key": options.apiKey,
@@ -51,6 +85,7 @@ describe("Bing Image Search", () => {
size: null,
};
const provider = new BingImageSearch(defaultOptions);
const assets = await provider.getAssets();
expect(assets.length).toEqual(assets.length);
expect(assets[0]).toEqual(expectedAsset);
+28 -3
Ver Arquivo
@@ -7,14 +7,18 @@ import { createQueryString } from "../../common/utils";
/**
* Options for Bing Image Search
* @member endpoint - The endpoint to use for the Bing Search API
* @member apiKey - Bing Search API Key (Cognitive Services)
* @member query - Query for Bing Search
* @member aspectRatio - Aspect Ratio for desired images
*/
export interface IBingImageSearchOptions {
endpoint?: string;
apiKey: string;
query: string;
aspectRatio: BingImageSearchAspectRatio;
size?: BingImageSearchSize;
licenseType?: BingImageSearchLicenseType;
}
/**
@@ -27,11 +31,29 @@ export enum BingImageSearchAspectRatio {
All = "All",
}
export enum BingImageSearchLicenseType {
All = "All",
Any = "Any",
Public = "Public",
Share = "Share",
ShareCommercially = "ShareCommercially",
Modify = "Modify",
ModifyCommercially = "ModifyCommercially",
}
export enum BingImageSearchSize {
All = "All",
Small = "Small",
Medium = "Medium",
Large = "Large",
Wallpaper = "Wallpaper",
}
/**
* Asset Provider for Bing Image Search
*/
export class BingImageSearch implements IAssetProvider {
private static SEARCH_URL = "https://api.cognitive.microsoft.com/bing/v7.0/images/search";
public static DefaultApiUrl = "https://api.cognitive.microsoft.com/bing";
constructor(private options: IBingImageSearchOptions) {
Guard.null(options);
@@ -44,11 +66,14 @@ export class BingImageSearch implements IAssetProvider {
const query = {
q: this.options.query,
aspect: this.options.aspectRatio,
license: this.options.licenseType || BingImageSearchLicenseType.All,
size: this.options.size || BingImageSearchSize.All,
};
const url = `${BingImageSearch.SEARCH_URL}?${createQueryString(query)}`;
const baseUrl = this.options.endpoint || BingImageSearch.DefaultApiUrl;
const apiUrl = `${baseUrl}/v7.0/images/search?${createQueryString(query)}`;
const response = await axios.get(url, {
const response = await axios.get(apiUrl, {
headers: {
"Ocp-Apim-Subscription-Key": this.options.apiKey,
"Accept": "application/json",