#Angular

0 关注者 · 5 帖子

Angular(或 AngularJS)是一个基于 JavaScript 的开源前端 Web 应用程序框架,主要由 Google 以及一个由个人和公司组成的社区负责维护,以解决开发单页应用程序时遇到的许多挑战。

官方网站

文章 Michael Lei · 八月 1, 2024 4m read

随着 IRIS 中向量数据类型和向量搜索功能的引入,应用程序的开发正在开启一个充满各种可能性的全新世界,其中一个应用程序示例是我最近在巴伦西亚卫生局的一次公开竞赛中看到的应用程序,他们要求提供一种工具,能够使用 AI 模型协助进行 ICD-10 编码。

我们如何实现与所要求的应用程序类似的应用程序? 我们来看看需要什么:

  1. ICD-10 代码列表,我们将使用它作为 RAG 应用程序的上下文,在纯文本中搜索诊断结果。
  2. 经过训练的模型,它会将文本向量化,我们将在其中查找 ICD-10 代码中的对应项。
  3. Python 库,用于对 ICD-10 代码和文本进行摄取和向量化。
  4. 一个支持文本的友好前端,我们会在其中查找可能的诊断结果。
  5. 从前端接收的请求的编排。

IRIS 为我们提供哪些功能来满足上述需求?

  1. CSV 导入,可以使用 RecordMapper 功能,也可以直接使用嵌入式 Python。
  2. 嵌入式 Python 使我们能够实现使用所选模型生成向量所需的 Python 代码。
  3. 发布将从前端应用程序调用的 REST API。
  4. 互操作性生产,以允许在 IRIS 中跟踪信息。

我们只需要看看开发的示例:

d[IA]gnosis

在本文中,您可以访问开发的应用程序,在后续文章中,我们将详细了解如何实现每个功能,包括模型的使用、向量的存储和向量搜索的使用。

我们来看看这个应用程序:

导入 ICD-10 代码

在配置屏幕中,我们知道了 CSV 文件必须使用的格式,以符合我们要导入的 ICD-10 代码。 加载和向量化过程会占用大量时间和资源,因此,为了防止所需空间超出分配的 RAM,在部署 Docker 容器时,不仅配置了 Docker 可用的 RAM 内存,还配置了磁盘存储器:

# iris  iris:    init:true    container_name:iris    build:      context:.      dockerfile:iris/Dockerfile    ports:      -52774:52773      -51774:1972    volumes:    -./shared:/shared    environment:    -ISC_DATA_DIRECTORY=/shared/durable    command:--check-capsfalse--ISCAgentfalse    mem_limit:30G    memswap_limit:32G

包含 ICD-10 代码的文件位于项目路径 /shared/cie10/icd10.csv 中,达到 100% 后,即可使用该应用程序。

在我们的应用程序中,我们定义了两个不同的诊断结果编码功能,一个基于系统中接收到的 HL7 消息,另一个基于纯文本。

从 HL7 中捕获诊断结果

项目中包含一些准备进行测试的 HL7 消息,只需将 /shared/hl7/messagesa01_en.hl7 文件复制到 /shared/HL7In 文件夹,相关的生产就会负责从中提取诊断结果,并显示在 Web 应用程序中:

在诊断结果请求屏幕中,我们可以看到通过 HL7 消息收到的所有诊断结果。 要将它们编码为 ICD-10,我们只需点击放大镜以显示与收到的诊断结果最接近的 ICD-10 代码列表:

选择后,我们将在列表中看到诊断结果及其相关的 ICD-10 代码。 点击带有信封图标的按钮,将使用原始代码生成一条消息,并在诊断结果部分包含所选新代码:

MSH|^~\&|HIS|HULP|EMPI||||ADT^A08|592956|P|2.5.1
EVN|A01|
PID|||1556655212^^^SERMAS^SN~922210^^^HULP^PI||GARCÍA PÉREZ^JUAN^^^||20150403|M|||PASEO PEDRO ÁLVAREZ 1951 CENTRO^^LEGANÉS^MADRID^28379^SPAIN||555283055^PRN^^JUAN.GARCIA@YAHOO.COM|||||||||||||||||N|
PV1||N
DG1|1||O10.91^Unspecified pre-existing hypertension complicating pregnancy^CIE10-ES|Gestational hypertension||A||

可以在路径 /shared/HL7Out 中找到此消息

以纯文本形式显示的诊断结果的屏幕截图

在“文本分析器”选项中,用户可以包含纯文本,并对其进行分析。 该应用程序将按 3 个词形还原的词(去除冠词、代词和其他不太相关的词)构成的元组进行搜索。 分析后,系统将向我们显示相关的带下划线的文本和找到的可能的诊断结果:

执行分析后,可以随时从分析历史记录中进行查询。

分析历史记录

执行的所有分析都会记录下来,可以随时查询,并且能够查看所有可用的 ICD-10 代码:

在下一篇文章中…

我们将看到,如何借助嵌入式 Python,使用特定的 LLM 模型对 ICD-10 代码进行向量化,从而将其用作上下文和自由文本。

如果您有任何疑问或建议,请随时对本文发表评论。

0
0 79
文章 Michael Lei · 十二月 7, 2022 11m read

Intersystems IRIS for Health 对 FHIR 行业标准提供了出色的支持。主要特点是:
1.FHIR 服务器
2. FHIR数据库
3. REST 和 ObjectScript API 用于 FHIR 资源(患者、问卷、疫苗等)的 CRUD 操作

本文演示了如何使用这些功能,并展示了用于创建和查看表单类型的 FHIR 资源的Angula前端。

第 1 步 - 使用 InterSystems IRIS for Health 部署您的 FHIR 服务器

要创建 FHIR 服务器,您必须将以下说明添加到 iris.script 文件中(来自:https://openexchange.intersystems.com/package/iris-fhir-template

0
0 156
文章 Michael Lei · 七月 18, 2022 8m read

Hi 大家好! 我是 Sergei Sarkisian,在InterSystems 做Angular 前端7年。Angular是非常流行的框架,我们的开发人员、客户和合作伙伴经常选择它来开发他们的应用程序。

我会写一系列的文章,涵盖Angular的不同方面:概念、方法、最佳实践、高级主题等等。这个系列的文章将针对那些已经熟悉Angular的人,不会涉及基本概念。由于我正在构建文章的路线图,我想从突出最近的Angular版本中的一些重要功能开始。

严格类型化表单

这可能是近几年来Angular最受欢迎的功能。有了Angular 14,开发者现在可以在Angular Reactive Forms中使用TypeScript的所有严格类型检查功能。

表单控制Formcontrol 类现在是通用的,并接受它所持有的值的类型。

/* Before Angular 14 */
const untypedControl = new FormControl(true);
untypedControl.setValue(100); // value is set, no errors

// Now
const strictlyTypedControl = new FormControl<boolean>(true);
strictlyTypedControl.setValue(100); // you will receive the type checking error message here

// Also in Angular 14
const strictlyTypedControl = new FormControl(true);
strictlyTypedControl.setValue(100); // you will receive the type checking error message here

正如你所见,第一个和最后一个例子几乎是一样的,但有不同的结果。这是因为在Angular 14中,新的FormControl类从开发者提供的初始值中推断出类型。因此,如果提供了true的值,Angular就为这个FormControl设置boolean | null的类型。.reset()方法需要可置空的值,如果没有提供值,就会置空这些值。

一个旧的、没有定义类型的FormControl类被转换为UntypedFormControl(对UntypedFormGroupUntypedFormArrayUntypedFormBuilder来说也是如此),它实际上是FormControl<any>的别名。如果你从以前的Angular版本升级,你所有提到的FormControl类将被Angular CLI替换为UntypedFormControl类。

Untyped* 类通常用以实现特定目标:

  1. 保持应用程序的工作方式与从以前的版本过渡之前完全一样(记住,新的FormControl将从初始值推断出类型)
  2. 确保所有的FormControl<any>的使用都是有意的。所以你需要自己将任何UntypedFormControl改为FormControl<any>
  3. 为了给开发者提供更多的灵活性(我们将在下面介绍这个问题)

记住,如果你的初始值是 "null",那么你将需要明确指定FormControl类型。另外,在TypeScript中有一个错误,如果你的初始值是 "false",也需要这样做。

对于表单组,你也可以定义接口,并把这个接口作为表单组的类型传递。在这种情况下,TypeScript将推断出FormGroup中的所有类型。

interface LoginForm {
    email: FormControl<string>;
    password?: FormControl<string>;
}

const login = new FormGroup<LoginForm>({
    email: new FormControl('', {nonNullable: true}),
    password: new FormControl('', {nonNullable: true}),
});

FormBuilder的方法.group()现在有了通用属性,可以接受你预定义的接口,就像上面的例子中我们手动创建了FormGroup。

interface LoginForm {
    email: FormControl<string>;
    password?: FormControl<string>;
}

const fb = new FormBuilder();
const login = fb.group<LoginForm>({
    email: '',
    password: '',
});

由于我们的接口只有原始的nonNullable类型,它可以用新的 "nonNullable "表单生成器属性来简化(它包含 "NonNullable FormBuilder表单生成器 "类实例,也可以直接创建):

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

❗ 请注意,如果你使用nonNullable的FormBuilder或者你在FormControl中设置了nonNullable的选项,那么当你调用.reset()方法时,它将使用初始FormControl值作为重置值。

另外,非常重要的一点是,this.form.value中的所有属性都将被标记为可选属性。像这样:

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

// login.value
// {
//   email?: string;
//   password?: string;
// }

发生这种情况是因为当你禁用表单组FormGroup内的任何表单控件FromControl时,这个表单控件的值将从form.value中删除。

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

login.get('email').disable();
console.log(login.value);

// {
//   password: ''
// }

要获得整个表单对象,你应该使用.getRawValue()方法::

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

login.get('email').disable();
console.log(login.getRawValue());

// {
//   email: '',
//   password: ''
// }

严格类型化表单的优势:

  1. 任何返回FormControl / FormGroup值的属性和方法现在都是严格类型的。例如:valuegetRawValue()valueChanges.
  2. 任何改变表单控件值的方法现在都是类型安全的:setValue(), patchValue(), updateValue()
  3. 表单控件现在是严格类型化的。它也适用于表单组的.get()方法。这也将防止你在编译时发生访问不存在的情况.

新的 FormRecord 类

新的 "表单组 "类的缺点是它失去了它的动态性质。一旦定义了,你将不能在运行中添加或删除表单控件。

为了解决这个问题,Angular提出了新的类--FormRecord'。FormRecord实际上与FormGroup`相同,但它是动态的,所有的表单控件都应该有相同的类型。.

folders: new FormRecord({
  home: new FormControl(true, { nonNullable: true }),
  music: new FormControl(false, { nonNullable: true })
});

// Add new FormContol to the group 
this.foldersForm.get('folders').addControl('videos', new FormControl(false, { nonNullable: true }));

// This will throw compilation error as control has different type
this.foldersForm.get('folders').addControl('books', new FormControl('Some string', { nonNullable: true }));

正如你所看到的,这里有另一个限制 - 所有的FormControls必须是相同的类型。如果你真的需要动态和异质的FormGroup,你应该使用UntypedFormGroup类来定义你的表单

无模块的 (独立standalone) 组件

这个特性仍然被标记为实验性的,但它是一个有趣的功能。它允许你定义组件、指令和管道,而不把它们包含在任何模块中。

这个概念还没有完全准备好,但我们已经能够在没有ngModules的情况下建立一个应用程序。

要定义一个独立的组件,你需要使用Component组件/Pipe管道/Directive Decorator指令装饰器中新的`standalone'属性:

@Component({
  selector: 'app-table',
  standalone: true,
  templateUrl: './table.component.html'
})
export class TableComponent {
}

在这种情况下,这个组件不能在任何NgModule中声明。但它可以在NgModules和其他独立组件中被导入。

每个独立的组件/管道/指令现在都有机制可以直接在Decorator装饰器中导入它的依赖项:

@Component({
  standalone: true,
  selector: 'photo-gallery',
  // an existing module is imported directly into a standalone component
  // CommonModule imported directly to use standard Angular directives like *ngIf
  // the standalone component declared above also imported directly
  imports: [CommonModule, MatButtonModule, TableComponent],
  template: `
    ...
    <button mat-button>Next Page</button>
    <app-table *ngIf="expression"></app-table>
  `,
})
export class PhotoGalleryComponent {
}

正如我上面提到的,你可以在任何现有的ngModule中导入独立的组件。不再需要导入整个共享模块,我们可以只导入我们真正需要的东西。这也是一个开始使用新的独立组件的好策略:

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule, TableComponent], // import our standalone TableComponent
  bootstrap: [AppComponent]
})
export class AppModule {}

你可以通过输入Angular CLI创建独立的组件:

ng g component --standalone user

Bootstrap 无模块的应用

如果你想摆脱你的应用程序中的所有ngModules,你将需要以不同的方式启动你的应用程序。Angular有新的函数,你需要在main.ts文件中调用这个函数:

bootstrapApplication(AppComponent);

这个函数的第二个参数将允许你定义你在你的应用程序中需要的提供者。由于大多数提供者通常存在于模块中,Angular(目前)需要为它们使用一个新的importProvidersFrom提取函数:

bootstrapApplication(AppComponent, { providers: [importProvidersFrom(HttpClientModule)] });

懒人加载独立组件的路线:

Angular有新的懒人-加载路由函数loadComponent,它的存在正是为了加载独立的组件:

{ 
  path: 'home',
  loadComponent: () => import('./home/home.component').then(m => m.HomeComponent)
}

loadChildren现在不仅允许懒人加载ngModule,而且还允许直接从路由文件中加载子路由:

{ 
  path: 'home',
  loadChildren: () => import('./home/home.routes').then(c => c.HomeRoutes)
}

关于本文的一些注意事项

  • 独立组件的功能仍处于实验阶段。它在未来会变得更好,因为它将移到Vite builder而不是Webpack,更好的工具,更快的构建时间,更强大的应用架构,更容易的测试等等。但现在这些东西都没有了,所以我们没有得到整个包,但至少我们可以开始用新的Angular范式开发我们的应用程序。
  • IDE和Angular工具还没有完全准备好静态地分析新的独立实体。因为你需要在每个独立实体中导入所有的依赖关系,万一你漏掉了什么,编译器也会漏掉它,并在运行时让你失败。这一点会随着时间的推移而得到改善,但现在需要开发人员更加关注导入。
  • 目前Angular中没有全局导入(例如在Vue中),所以你需要在每个独立实体中完全导入每个依赖。我希望这个问题能在未来的版本中得到解决,因为在我看来,这个功能的主要目标是减少模板,让事情变得更简单。

先写到这,谢谢大家!

0
0 736
文章 Michael Lei · 六月 11, 2022 2m read

在检查我们的^pButtons(在IRIS中改名为^SystemPerformance)性能监控工具的文档时,一位客户告诉我。"我理解所有内容,但我希望它能更简单......更容易定义配置文件,管理它们等等"。

在这次会议之后,我认为尝试为其提供一些更简单的人机界面是一个不错的试验。

这方面的第一步是在现有的pButtons例程上包裹一个基于类的API。

我还能够添加一些更多的 "功能",比如显示当前正在运行的配置文件,它们剩余的运行时间,以前运行的进程等等。

下一步是在这个API的基础上添加一个REST API类。

有了这个工件(pButtons REST API),人们就可以在上面建立一个比较时髦的用户界面。

举个🌰: -

0
0 194
文章 Hao Ma · 一月 15, 2021 6m read

假设您想编写一些真正的web应用程序,例如medium.com网站的简单克隆。这类应用程序可以在后端使用任何不同的语言编写,也可以使用前端的任何框架编写。编写这样一个应用程序有很多方法,你也可以看看这个项目。它为完全相同的应用程序提供了一堆前端和后端实现。您可以轻松组合它们,任何所选前端应该与任何后端搭配。

我来介绍一下这个使用后端InterSystems IRIS来实现后端的相同的应用程序。  

0
0 259