Skip to content

Commit

Permalink
#1172 extend ketcher api add possibility to run server functions (#1173)
Browse files Browse the repository at this point in the history
* Add get server to ketcher

* Add server method in ketcher

* Refactor server method in ketcher

* Fix ts errors

* Fix prettier

* Refactored indigo functions

* Refactor indigo methods
  • Loading branch information
ViktoriiaFedotkina authored Jan 19, 2022
1 parent ea02d4e commit 1f1af1b
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 13 deletions.
212 changes: 212 additions & 0 deletions packages/ketcher-core/src/application/indigo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/****************************************************************************
* Copyright 2021 EPAM Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/

import {
AutomapMode,
CalculateProps,
CalculateResult,
CheckResult,
CheckTypes,
ChemicalMimeType,
ConvertResult,
InfoResult,
OutputFormatType,
StructService
} from 'domain/services'
import { StructOrString } from 'application/indigo.types'
import { KetSerializer } from 'domain/serializers'
import { Struct } from 'domain/entities'

const defaultTypes: Array<CheckTypes> = [
'radicals',
'pseudoatoms',
'stereo',
'query',
'overlapping_atoms',
'overlapping_bonds',
'rgroups',
'chiral',
'3d'
]
const defaultCalcProps: Array<CalculateProps> = [
'molecular-weight',
'most-abundant-mass',
'monoisotopic-mass',
'gross',
'mass-composition'
]

type ConvertOptions = {
outputFormat?: ChemicalMimeType
}
type AutomapOptions = {
mode?: AutomapMode
}
type CheckOptions = {
types?: Array<CheckTypes>
}
type CalculateOptions = {
properties?: Array<CalculateProps>
}
type RecognizeOptions = {
version?: string
}
type GenerateImageOptions = {
outputFormat?: OutputFormatType
backgroundColor?: string
}

function convertStructToString(
struct: StructOrString,
serializer: KetSerializer
): string {
if (typeof struct !== 'string') {
const aidMap = new Map()
const result = struct.clone(null, null, false, aidMap)

return serializer.serialize(result)
}

return struct
}

export class Indigo {
#structService: StructService
#ketSerializer: KetSerializer

constructor(structService) {
this.#structService = structService
this.#ketSerializer = new KetSerializer()
}

info(): Promise<InfoResult> {
return this.#structService.info()
}

convert(
struct: StructOrString,
options?: ConvertOptions
): Promise<ConvertResult> {
const outputFormat = options?.outputFormat || ChemicalMimeType.KET

return this.#structService.convert({
struct: convertStructToString(struct, this.#ketSerializer),
output_format: outputFormat
})
}

layout(struct: StructOrString): Promise<Struct> {
return this.#structService
.layout({
struct: convertStructToString(struct, this.#ketSerializer),
output_format: ChemicalMimeType.KET
})
.then((data) => this.#ketSerializer.deserialize(data.struct))
}

clean(struct: StructOrString): Promise<Struct> {
return this.#structService
.clean({
struct: convertStructToString(struct, this.#ketSerializer),
output_format: ChemicalMimeType.KET
})
.then((data) => this.#ketSerializer.deserialize(data.struct))
}

aromatize(struct: StructOrString): Promise<Struct> {
return this.#structService
.aromatize({
struct: convertStructToString(struct, this.#ketSerializer),
output_format: ChemicalMimeType.KET
})
.then((data) => this.#ketSerializer.deserialize(data.struct))
}

dearomatize(struct: StructOrString): Promise<Struct> {
return this.#structService
.dearomatize({
struct: convertStructToString(struct, this.#ketSerializer),
output_format: ChemicalMimeType.KET
})
.then((data) => this.#ketSerializer.deserialize(data.struct))
}

calculateCip(struct: StructOrString): Promise<Struct> {
return this.#structService
.calculateCip({
struct: convertStructToString(struct, this.#ketSerializer),
output_format: ChemicalMimeType.KET
})
.then((data) => this.#ketSerializer.deserialize(data.struct))
}

automap(struct: StructOrString, options?: AutomapOptions): Promise<Struct> {
const mode = options?.mode || 'discard'

return this.#structService
.automap({
struct: convertStructToString(struct, this.#ketSerializer),
output_format: ChemicalMimeType.KET,
mode
})
.then((data) => this.#ketSerializer.deserialize(data.struct))
}

check(struct: StructOrString, options?: CheckOptions): Promise<CheckResult> {
const types = options?.types || defaultTypes

return this.#structService.check({
struct: convertStructToString(struct, this.#ketSerializer),
types
})
}

calculate(
struct: StructOrString,
options?: CalculateOptions
): Promise<CalculateResult> {
const properties = options?.properties || defaultCalcProps

return this.#structService.calculate({
struct: convertStructToString(struct, this.#ketSerializer),
properties
})
}

recognize(image: Blob, options?: RecognizeOptions): Promise<Struct> {
const version = options?.version || ''

return this.#structService
.recognize(image, version)
.then((data) => this.#ketSerializer.deserialize(data.struct))
}

generateImageAsBase64(
struct: StructOrString,
options?: GenerateImageOptions
): Promise<string> {
const outputFormat = options?.outputFormat || 'png'
const backgroundColor = options?.backgroundColor || ''

return this.#structService.generateImageAsBase64(
convertStructToString(struct, this.#ketSerializer),
{
outputFormat,
backgroundColor
}
)
}
}
19 changes: 19 additions & 0 deletions packages/ketcher-core/src/application/indigo.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/****************************************************************************
* Copyright 2021 EPAM Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/

import { Struct } from 'domain/entities'

export type StructOrString = Struct | string
11 changes: 9 additions & 2 deletions packages/ketcher-core/src/application/ketcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@

import {
FormatterFactory,
SupportedFormat,
identifyStructFormat
identifyStructFormat,
SupportedFormat
} from './formatters'
import { GenerateImageOptions, StructService } from 'domain/services'

import { Editor } from './editor'
import { MolfileFormat } from 'domain/serializers'
import { Struct } from 'domain/entities'
import assert from 'assert'
import { Indigo } from 'application/indigo'

function parseStruct(structStr: string, structService: StructService) {
const format = identifyStructFormat(structStr)
Expand All @@ -47,6 +48,7 @@ export class Ketcher {
#structService: StructService
#formatterFactory: FormatterFactory
#editor: Editor
#indigo: Indigo

get editor(): Editor {
return this.#editor
Expand All @@ -64,6 +66,11 @@ export class Ketcher {
this.#editor = editor
this.#structService = structService
this.#formatterFactory = formatterFactory
this.#indigo = new Indigo(this.#structService)
}

get indigo() {
return this.#indigo
}

getSmiles(isExtended = false): Promise<string> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,21 @@ export interface WithSelection {
selected?: Array<number>
}

export type CheckTypes =
| 'radicals'
| 'pseudoatoms'
| 'stereo'
| 'query'
| 'overlapping_atoms'
| 'overlapping_bonds'
| 'rgroups'
| 'chiral'
| '3d'
| 'chiral_flag'
| 'valence'

export interface CheckData extends WithStruct {
types: Array<string>
types: Array<CheckTypes>
}

export interface CheckResult {
Expand Down Expand Up @@ -78,16 +91,23 @@ export interface CalculateCipData extends WithStruct, WithOutputFormat {}

export interface CalculateCipResult extends WithStruct, WithFormat {}

export type CalculateProps =
| 'molecular-weight'
| 'most-abundant-mass'
| 'monoisotopic-mass'
| 'gross'
| 'mass-composition'

export interface CalculateData extends WithStruct, WithSelection {
properties: Array<string>
properties: Array<CalculateProps>
}

export interface CalculateResult {
[key: string]: string | number | boolean
}
export type CalculateResult = Record<CalculateProps, string | number | boolean>

export type AutomapMode = 'discard' | 'keep' | 'alter' | 'clear'

export interface AutomapData extends WithStruct, WithOutputFormat {
mode: string
mode: AutomapMode
}

export interface AutomapResult extends WithStruct, WithFormat {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ export interface CalculateCipCommandData
WithStruct,
WithFormat {}

export type CalculateProps =
| 'molecular-weight'
| 'most-abundant-mass'
| 'monoisotopic-mass'
| 'gross'
| 'gross-formula'
| 'mass-composition'

export interface CalculateCommandData
extends CommandData,
WithStruct,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
AutomapCommandData,
CalculateCipCommandData,
CalculateCommandData,
CalculateProps,
CheckCommandData,
CleanCommandData,
Command,
Expand Down Expand Up @@ -116,8 +117,8 @@ function convertMimeTypeToOutputFormat(
return format
}

function mapCalculatedPropertyName(property: string) {
let mappedProperty: string | undefined
function mapCalculatedPropertyName(property: CalculateProps) {
let mappedProperty: CalculateProps | undefined
switch (property) {
case 'gross-formula': {
mappedProperty = 'gross'
Expand Down Expand Up @@ -544,18 +545,20 @@ class IndigoService implements StructService {
worker.terminate()
const msg: OutputMessage<string> = e.data
if (!msg.hasError) {
const calculatedProperties = JSON.parse(msg.payload!) as KeyValuePair
const calculatedProperties: CalculateResult = JSON.parse(msg.payload!)
const result: CalculateResult = Object.entries(
calculatedProperties
).reduce((acc, curr) => {
const [key, value] = curr
const mappedPropertyName = mapCalculatedPropertyName(key)
const mappedPropertyName = mapCalculatedPropertyName(
key as CalculateProps
)
if (properties.includes(mappedPropertyName)) {
acc[mappedPropertyName] = value
}

return acc
}, {})
}, {} as CalculateResult)
resolve(result)
} else {
reject(msg.error)
Expand Down

0 comments on commit 1f1af1b

Please sign in to comment.