@cloudbase/ai 3.6.2 → 3.6.4-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/miniprogram/index.js +1 -1
  2. package/dist/miniprogram/index.js.LICENSE.txt +2 -2
  3. package/package.json +8 -4
  4. package/.eslintignore +0 -2
  5. package/.eslintrc.js +0 -16
  6. package/src/AI.ts +0 -191
  7. package/src/bot/index.ts +0 -278
  8. package/src/bot/types.ts +0 -165
  9. package/src/errors.ts +0 -23
  10. package/src/eventsource_parser/index.ts +0 -2
  11. package/src/eventsource_parser/parse.ts +0 -169
  12. package/src/eventsource_parser/stream.ts +0 -35
  13. package/src/eventsource_parser/types.ts +0 -90
  14. package/src/index.ts +0 -165
  15. package/src/models/Ark/index.ts +0 -94
  16. package/src/models/Ark/type.ts +0 -82
  17. package/src/models/DashScope/index.ts +0 -97
  18. package/src/models/DashScope/type.ts +0 -76
  19. package/src/models/DeepSeek/index.ts +0 -80
  20. package/src/models/Default/index.ts +0 -70
  21. package/src/models/HunYuan/index.ts +0 -94
  22. package/src/models/HunYuan/type.ts +0 -85
  23. package/src/models/HunYuan/util.ts +0 -60
  24. package/src/models/HunYuanBeta/index.ts +0 -83
  25. package/src/models/HunYuanExp/index.ts +0 -80
  26. package/src/models/HunYuanOpen/index.ts +0 -83
  27. package/src/models/Moonshot/index.ts +0 -95
  28. package/src/models/Moonshot/type.ts +0 -82
  29. package/src/models/Yi/index.ts +0 -100
  30. package/src/models/Yi/type.ts +0 -77
  31. package/src/models/ZhiPu/index.ts +0 -104
  32. package/src/models/ZhiPu/type.ts +0 -71
  33. package/src/models/image-model.ts +0 -100
  34. package/src/models/index.ts +0 -41
  35. package/src/models/model.ts +0 -425
  36. package/src/type.ts +0 -362
  37. package/src/utils.ts +0 -198
  38. package/tsconfig.esm.json +0 -16
  39. package/tsconfig.json +0 -16
  40. package/webpack/web.prod.js +0 -100
  41. package/webpack/webpack.miniprogram.js +0 -24
@@ -1,80 +0,0 @@
1
- /* eslint-disable @typescript-eslint/naming-convention */
2
- /* eslint-disable eqeqeq */
3
- import {
4
- createAsyncIterable,
5
- TransformStream,
6
- toPolyfillReadable,
7
- intoStandardStream,
8
- isToolCallAssistantMessage,
9
- } from '../../utils'
10
- import type {
11
- ModelReq,
12
- BaseChatModelInput,
13
- SimpleChatModel,
14
- DoStreamOutput,
15
- BaseDoStreamOutputChunk,
16
- DoGenerateOutput,
17
- } from '../../type'
18
- import { processInput } from '../HunYuan/util'
19
- import { HunYuanGenerateTextOutput, HunYuanStreamTextOutput } from '../HunYuan/type'
20
-
21
- export class HunYuanExpSimpleModel implements SimpleChatModel {
22
- public subUrl = 'hunyuan-exp/chat/completions'
23
- constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
24
- if (subUrl != null) {
25
- this.subUrl = subUrl
26
- }
27
- }
28
-
29
- private get url() {
30
- return `${this.baseUrl}/${this.subUrl}`
31
- }
32
-
33
- public async doGenerate(data: BaseChatModelInput): Promise<DoGenerateOutput> {
34
- const res = (await this.req({
35
- url: this.url,
36
- data: {
37
- ...processInput(data),
38
- stream: false,
39
- },
40
- stream: false,
41
- })) as HunYuanGenerateTextOutput
42
- return { ...res, rawResponse: res }
43
- }
44
-
45
- public async doStream(data: BaseChatModelInput): Promise<DoStreamOutput> {
46
- let isToolCall: null | boolean = null
47
-
48
- const _stream = await this.req({
49
- url: this.url,
50
- data: {
51
- ...processInput(data),
52
- stream: true,
53
- },
54
- stream: true,
55
- })
56
- const stream = toPolyfillReadable(_stream) as typeof _stream
57
-
58
- const hunyuanBetaStream = intoStandardStream<HunYuanStreamTextOutput>(stream)
59
- const streamWithRaw = hunyuanBetaStream.pipeThrough(new TransformStream<HunYuanStreamTextOutput, BaseDoStreamOutputChunk & { rawResponse?: any }>({
60
- transform(chunk, controller) {
61
- const newChoices = chunk.choices.map((choice) => {
62
- const message = choice.delta
63
- if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
64
- if (isToolCall) {
65
- return {
66
- ...choice,
67
- finish_reason: 'tool_calls',
68
- delta: message,
69
- }
70
- }
71
- return choice
72
- })
73
- const newChunk = { ...chunk, choices: newChoices }
74
- controller.enqueue({ ...newChunk, rawResponse: chunk })
75
- },
76
- }),)
77
-
78
- return createAsyncIterable(streamWithRaw)
79
- }
80
- }
@@ -1,83 +0,0 @@
1
- /* eslint-disable eqeqeq */
2
- import {
3
- createAsyncIterable,
4
- TransformStream,
5
- toPolyfillReadable,
6
- intoStandardStream,
7
- isToolCallAssistantMessage,
8
- } from '../../utils'
9
- import type {
10
- ModelReq,
11
- BaseChatModelInput,
12
- SimpleChatModel,
13
- DoStreamOutput,
14
- BaseDoStreamOutputChunk,
15
- DoGenerateOutput,
16
- ReqOptions,
17
- } from '../../type'
18
- import { processInput } from '../HunYuan/util'
19
- import { HunYuanGenerateTextOutput, HunYuanStreamTextOutput } from '../HunYuan/type'
20
-
21
- export class HunYuanOpenSimpleModel implements SimpleChatModel {
22
- public subUrl = 'hunyuan-open/v1/chat/completions'
23
- constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
24
- if (subUrl != null) {
25
- this.subUrl = subUrl
26
- }
27
- }
28
-
29
- private get url() {
30
- return `${this.baseUrl}/${this.subUrl}`
31
- }
32
-
33
- public async doGenerate(data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
34
- const res = (await this.req({
35
- url: this.url,
36
- data: {
37
- ...processInput(data),
38
- stream: false,
39
- },
40
- stream: false,
41
- timeout: options?.timeout,
42
- })) as HunYuanGenerateTextOutput
43
- return { ...res, rawResponse: res }
44
- }
45
-
46
- public async doStream(data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
47
- let isToolCall: null | boolean = null
48
-
49
- // eslint-disable-next-line @typescript-eslint/naming-convention
50
- const _stream = await this.req({
51
- url: this.url,
52
- data: {
53
- ...processInput(data),
54
- stream: true,
55
- },
56
- stream: true,
57
- timeout: options?.timeout,
58
- })
59
- const stream = toPolyfillReadable(_stream) as typeof _stream
60
-
61
- const hunyuanBetaStream = intoStandardStream<HunYuanStreamTextOutput>(stream)
62
- const streamWithRaw = hunyuanBetaStream.pipeThrough(new TransformStream<HunYuanStreamTextOutput, BaseDoStreamOutputChunk & { rawResponse?: any }>({
63
- transform(chunk, controller) {
64
- const newChoices = chunk.choices.map((choice) => {
65
- const message = choice.delta
66
- if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
67
- if (isToolCall) {
68
- return {
69
- ...choice,
70
- finish_reason: 'tool_calls',
71
- delta: message,
72
- }
73
- }
74
- return choice
75
- })
76
- const newChunk = { ...chunk, choices: newChoices }
77
- controller.enqueue({ ...newChunk, rawResponse: chunk })
78
- },
79
- }),)
80
-
81
- return createAsyncIterable(streamWithRaw)
82
- }
83
- }
@@ -1,95 +0,0 @@
1
- /* eslint-disable eqeqeq */
2
- import {
3
- createAsyncIterable,
4
- TransformStream,
5
- toPolyfillReadable,
6
- intoStandardStream,
7
- isToolCallAssistantMessage,
8
- } from '../../utils'
9
- import type { MoonshotGenerateTextOutput, MoonshotStreamTextOutput, MoonshotInputData } from './type'
10
- import type {
11
- ModelReq,
12
- BaseDoStreamOutputChunk,
13
- DoGenerateOutput,
14
- DoStreamOutput,
15
- SimpleChatModel,
16
- BaseChatModelInput,
17
- ReqOptions,
18
- } from '../../type'
19
-
20
- function processInput(input: BaseChatModelInput): MoonshotInputData {
21
- // eslint-disable-next-line @typescript-eslint/naming-convention
22
- const { messages, model, temperature, tools, top_p } = input
23
-
24
- return {
25
- ...input,
26
- messages,
27
- model,
28
- tools,
29
- top_p,
30
- temperature,
31
- }
32
- }
33
-
34
- export class MoonshotSimpleModel implements SimpleChatModel {
35
- public subUrl = 'moonshot/v1/chat/completions'
36
- constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
37
- if (subUrl != null) {
38
- this.subUrl = subUrl
39
- }
40
- }
41
-
42
- private get url() {
43
- return `${this.baseUrl}/${this.subUrl}`
44
- }
45
-
46
- public async doGenerate(data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
47
- const res = (await this.req({
48
- url: this.url,
49
- data: {
50
- ...processInput(data),
51
- stream: false,
52
- },
53
- stream: false,
54
- timeout: options?.timeout,
55
- })) as MoonshotGenerateTextOutput
56
- return { ...res, rawResponse: res }
57
- }
58
-
59
- public async doStream(data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
60
- let isToolCall: null | boolean = null
61
- // eslint-disable-next-line @typescript-eslint/naming-convention
62
- const _stream = await this.req({
63
- url: this.url,
64
- data: {
65
- ...processInput(data),
66
- stream: true,
67
- },
68
- stream: true,
69
- timeout: options?.timeout,
70
- })
71
- const stream = toPolyfillReadable(_stream) as typeof _stream
72
-
73
- const arkStream = intoStandardStream<MoonshotStreamTextOutput>(stream)
74
- const streamWithRaw = arkStream.pipeThrough(new TransformStream<MoonshotStreamTextOutput, BaseDoStreamOutputChunk & { rawResponse?: any }>({
75
- transform(chunk, controller) {
76
- const newChoices = chunk.choices.map((choice) => {
77
- const message = choice.delta
78
- if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
79
- if (isToolCall) {
80
- return {
81
- ...choice,
82
- finish_reason: 'tool_calls' as const,
83
- delta: message,
84
- }
85
- }
86
- return choice
87
- })
88
- const newChunk = { ...chunk, choices: newChoices }
89
- controller.enqueue({ ...newChunk, rawResponse: chunk })
90
- },
91
- }),)
92
-
93
- return createAsyncIterable(streamWithRaw)
94
- }
95
- }
@@ -1,82 +0,0 @@
1
- type SystemMessage = {
2
- role: 'system'
3
- content: string
4
- }
5
-
6
- type UserMessage = {
7
- role: 'user'
8
- content: string
9
- }
10
-
11
- type AssistantMessage = {
12
- role: 'assistant'
13
- content?: string
14
- tool_calls?: Array<{
15
- id: string
16
- type: string
17
- function?: { name: string; arguments: string }
18
- }>
19
- }
20
-
21
- type ToolMessage = {
22
- role: 'tool'
23
- content: string
24
- tool_call_id: string
25
- }
26
-
27
- type MoonshotMessage = SystemMessage | UserMessage | AssistantMessage | ToolMessage
28
-
29
- export type MoonshotInputData = {
30
- messages: Array<MoonshotMessage>
31
- model: string
32
- max_tokens?: number
33
- temperature?: number
34
- top_p?: number
35
- n?: number
36
- tools?: Array<{
37
- type: string
38
- function: { name: string; description: string; parameters: object }
39
- }>
40
- presence_penalty?: number
41
- frequency_penalty?: number
42
- response_format?: object
43
- stop?: string | Array<string>
44
- }
45
-
46
- // todo: more precise
47
- export type MoonshotGenerateTextOutput = {
48
- choices: Array<{
49
- finish_reason: string
50
- message: {
51
- content: string
52
- role: 'assistant'
53
- tool_calls?: Array<ToolCall>
54
- }
55
- }>
56
- usage: {
57
- prompt_tokens: number
58
- completion_tokens: number
59
- total_tokens: number
60
- }
61
- }
62
- // todo: more precise
63
- export type MoonshotStreamTextOutput = {
64
- choices: Array<{
65
- delta: {
66
- content: string
67
- tool_calls?: Array<ToolCall>
68
- role: 'assistant'
69
- }
70
- finish_reason: string
71
- }>
72
- usage?: {
73
- prompt_tokens: number
74
- completion_tokens: number
75
- total_tokens: number
76
- }
77
- }
78
- type ToolCall = {
79
- id: string
80
- type: string
81
- function: { name: string; arguments: string }
82
- }
@@ -1,100 +0,0 @@
1
- /* eslint-disable @typescript-eslint/naming-convention */
2
- /* eslint-disable eqeqeq */
3
- import {
4
- createAsyncIterable,
5
- TransformStream,
6
- toPolyfillReadable,
7
- intoStandardStream,
8
- isToolCallAssistantMessage,
9
- } from '../../utils'
10
- import type { YiInput, YiGenerateOutput, YiStreamOutput } from './type'
11
- import type {
12
- ModelReq,
13
- BaseChatModelInput,
14
- DoGenerateOutput,
15
- DoStreamOutput,
16
- BaseDoStreamOutputChunk,
17
- SimpleChatModel,
18
- ReqOptions,
19
- } from '../../type'
20
-
21
- function processInput(input: BaseChatModelInput): YiInput {
22
- const { messages, model, temperature, tools, top_p } = input
23
-
24
- return {
25
- ...input,
26
- messages,
27
- model,
28
- tools,
29
- top_p,
30
- temperature,
31
- }
32
- }
33
-
34
- export class YiSimpleModel implements SimpleChatModel {
35
- public subUrl = '01-ai/v1/chat/completions'
36
-
37
- constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
38
- if (subUrl != null) {
39
- this.subUrl = subUrl
40
- }
41
- }
42
-
43
- private get url() {
44
- return `${this.baseUrl}/${this.subUrl}`
45
- }
46
-
47
- public async doGenerate(data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
48
- const res = (await this.req({
49
- url: this.url,
50
- data: {
51
- ...processInput(data),
52
- stream: false,
53
- },
54
- stream: false,
55
- timeout: options?.timeout,
56
- })) as YiGenerateOutput
57
- return { ...res, rawResponse: res }
58
- }
59
-
60
- public async doStream(data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
61
- let isToolCall: null | boolean = null
62
- const _stream = await this.req({
63
- url: this.url,
64
- data: {
65
- ...processInput(data),
66
- stream: true,
67
- },
68
- stream: true,
69
- timeout: options?.timeout,
70
- })
71
- const stream = toPolyfillReadable(_stream) as typeof _stream
72
-
73
- const arkStream = intoStandardStream<YiStreamOutput>(stream)
74
- const streamWithRaw = arkStream.pipeThrough(new TransformStream<YiStreamOutput, BaseDoStreamOutputChunk & { rawResponse?: any }>({
75
- transform(chunk, controller) {
76
- // 非常奇葩
77
- if (!(chunk?.choices?.[0]?.delta?.content || chunk?.choices?.[0]?.delta?.tool_calls)) return
78
-
79
- const newChoices = chunk.choices.map((choice) => {
80
- const message = Object.assign(choice.delta, { role: 'assistant' }) as typeof choice.delta & {
81
- role: 'assistant'
82
- }
83
- if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
84
- if (isToolCall) {
85
- return {
86
- ...choice,
87
- finish_reason: 'tool_calls' as const,
88
- delta: message,
89
- }
90
- }
91
- return { ...choice, delta: message }
92
- })
93
- const newChunk = { ...chunk, choices: newChoices }
94
- controller.enqueue({ ...newChunk, rawResponse: chunk })
95
- },
96
- }),)
97
-
98
- return createAsyncIterable(streamWithRaw)
99
- }
100
- }
@@ -1,77 +0,0 @@
1
- type SystemMessage = {
2
- role: 'system'
3
- content: string
4
- }
5
-
6
- type UserMessage = {
7
- role: 'user'
8
- content: string
9
- }
10
-
11
- type AssistantMessage =
12
- | {
13
- role: 'assistant'
14
- content: string
15
- }
16
- | {
17
- role: 'assistant'
18
- tool_calls: Array<ToolCall>
19
- content?: string
20
- }
21
-
22
- type ToolMessage = {
23
- role: 'tool'
24
- content: string
25
- tool_call_id: string
26
- }
27
-
28
- type YiMessage = SystemMessage | UserMessage | AssistantMessage | ToolMessage
29
-
30
- export type YiInput = {
31
- model: string
32
- messages: Array<YiMessage>
33
- temperature?: number
34
- top_p?: number
35
- tools?: Array<{
36
- type: string
37
- function: { name: string; description: string; parameters: object }
38
- }>
39
- }
40
-
41
- type ToolCall = {
42
- id: string
43
- type: string
44
- function: { name: string; arguments: string }
45
- }
46
-
47
- export type YiGenerateOutput = {
48
- choices: Array<{
49
- finish_reason: string
50
- message: {
51
- content: string
52
- role: 'assistant'
53
- tool_calls?: Array<ToolCall>
54
- }
55
- }>
56
- usage: {
57
- prompt_tokens: number
58
- completion_tokens: number
59
- total_tokens: number
60
- }
61
- }
62
-
63
- export type YiStreamOutput = {
64
- choices: Array<{
65
- delta: {
66
- content: string
67
- tool_calls?: Array<ToolCall>
68
- role?: 'assistant'
69
- }
70
- finish_reason: string
71
- }>
72
- usage?: {
73
- prompt_tokens: number
74
- completion_tokens: number
75
- total_tokens: number
76
- }
77
- }
@@ -1,104 +0,0 @@
1
- /* eslint-disable eqeqeq */
2
- /* eslint-disable @typescript-eslint/naming-convention */
3
- import {
4
- createAsyncIterable,
5
- TransformStream,
6
- toPolyfillReadable,
7
- intoStandardStream,
8
- isToolCallAssistantMessage,
9
- } from '../../utils'
10
- import type { ZhiPuGenerateTextOutput, ZhiPuInputData, ZhiPuStreamTextOutput } from './type'
11
- import type {
12
- ModelReq,
13
- BaseChatModelInput,
14
- SimpleChatModel,
15
- DoStreamOutput,
16
- BaseDoStreamOutputChunk,
17
- DoGenerateOutput,
18
- ReqOptions,
19
- } from '../../type'
20
-
21
- function processInput(input: BaseChatModelInput): ZhiPuInputData {
22
- const { messages, model, temperature, tool_choice, tools, top_p } = input
23
-
24
- const processToolChoice = () => {
25
- if (tool_choice && tool_choice !== 'auto') {
26
- console.warn('`tool_choice` is not \'auto\'')
27
- }
28
- return tool_choice as any
29
- }
30
-
31
- return {
32
- ...input,
33
- messages,
34
- model,
35
- temperature,
36
- tool_choice: processToolChoice(),
37
- tools,
38
- top_p,
39
- }
40
- }
41
-
42
- export class ZhiPuSimpleModel implements SimpleChatModel {
43
- public subUrl = 'zhipu/api/paas/v4/chat/completions'
44
- constructor(private req: ModelReq, public baseUrl: string, subUrl?: string) {
45
- if (subUrl != null) {
46
- this.subUrl = subUrl
47
- }
48
- }
49
-
50
- private get url() {
51
- return `${this.baseUrl}/${this.subUrl}`
52
- }
53
-
54
- public async doGenerate(_data: BaseChatModelInput, options?: ReqOptions): Promise<DoGenerateOutput> {
55
- const data = processInput(_data)
56
- const res = (await this.req({
57
- url: this.url,
58
- data: {
59
- ...data,
60
- stream: false,
61
- },
62
- stream: false,
63
- timeout: options?.timeout,
64
- })) as ZhiPuGenerateTextOutput
65
- return { ...res, rawResponse: res }
66
- }
67
-
68
- public async doStream(_data: BaseChatModelInput, options?: ReqOptions): Promise<DoStreamOutput> {
69
- const data = processInput(_data)
70
- let isToolCall: null | boolean = null
71
- const _stream = await this.req({
72
- url: this.url,
73
- data: {
74
- ...data,
75
- stream: true,
76
- },
77
- stream: true,
78
- timeout: options?.timeout,
79
- })
80
- const stream = toPolyfillReadable(_stream) as typeof _stream
81
-
82
- const zhipuStream = intoStandardStream<ZhiPuStreamTextOutput>(stream)
83
- const streamWithRaw = zhipuStream.pipeThrough(new TransformStream<ZhiPuStreamTextOutput, BaseDoStreamOutputChunk & { rawResponse?: any }>({
84
- transform(chunk, controller) {
85
- const newChoices = chunk.choices.map((choice) => {
86
- const message = choice.delta
87
- if (isToolCall == null) isToolCall = isToolCallAssistantMessage(message)
88
- if (isToolCall) {
89
- return {
90
- ...choice,
91
- finish_reason: 'tool_calls' as const,
92
- delta: message,
93
- }
94
- }
95
- return choice
96
- })
97
- const newChunk = { ...chunk, choices: newChoices }
98
- controller.enqueue({ ...newChunk, rawResponse: chunk })
99
- },
100
- }),)
101
-
102
- return createAsyncIterable(streamWithRaw)
103
- }
104
- }
@@ -1,71 +0,0 @@
1
- import { ChatModelMessage } from '../../type'
2
-
3
- type SystemMessage = {
4
- role: 'system'
5
- content: string
6
- }
7
-
8
- type UserMessage = {
9
- role: 'user'
10
- content: string
11
- }
12
-
13
- type AssistantMessage = {
14
- role: 'assistant'
15
- content?: string
16
- tool_calls?: Array<{
17
- id: string
18
- type: string
19
- function?: { name: string; arguments: string }
20
- }>
21
- }
22
-
23
- type ToolMessage = {
24
- role: 'tool'
25
- content: string
26
- tool_call_id: string
27
- }
28
-
29
- type ZhiPuMessage = SystemMessage | UserMessage | AssistantMessage | ToolMessage
30
-
31
- export type ZhiPuInputData = {
32
- model: string
33
- messages: Array<ZhiPuMessage>
34
- request_id?: string
35
- do_sample?: boolean
36
- temperature?: number
37
- top_p?: number
38
- max_tokens?: number
39
- stop?: Array<string>
40
- tools?: Array<{
41
- type: string
42
- function: { name: string; description: string; parameters: object }
43
- }>
44
- tool_choice?: 'auto'
45
- user_id?: string
46
- }
47
-
48
- export type ZhiPuGenerateTextOutput = {
49
- choices?: Array<{
50
- finish_reason?: 'stop' | 'tool_calls' | 'length' | 'sensitive' | 'network_error'
51
- message?: ChatModelMessage
52
- }>
53
- usage?: {
54
- completion_tokens: number
55
- prompt_tokens: number
56
- total_tokens: number
57
- }
58
- }
59
-
60
- export type ZhiPuStreamTextOutput = {
61
- choices?: Array<{
62
- index: number
63
- finish_reason?: 'stop' | 'tool_calls' | 'length' | 'sensitive' | 'network_error'
64
- delta?: ChatModelMessage
65
- }>
66
- usage?: {
67
- completion_tokens: number
68
- prompt_tokens: number
69
- total_tokens: number
70
- }
71
- }