Skip to content

Commit ff27d85

Browse files
committed
Examples: AI: Server: Converted it to promises #70
1 parent eeaf1a3 commit ff27d85

15 files changed

Lines changed: 92 additions & 140 deletions

File tree

Examples/AI/Server/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ AI_SERVER_PORT=3000
1515
# Ollama does not have API key access.
1616
# Look here for currently installable models: https://ollama.com/library
1717
OLLAMA_BASE_URL="http://localhost:11434"
18-
OLLAMA_MODELS="llama3.2"
18+
OLLAMA_MODELS="gemma3:1b"
1919

2020
# OpenAI / GPT*, O*
2121
# Look here for current models: https://platform.openai.com/docs/models

Examples/AI/Server/src/AiServer.st

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ For an example result see class AiProviders."
6969

7070
onProviders: request response: response
7171
| providers |
72-
7372
providers := Ai providers.
7473
response send: providers toObject.
7574
self log: 'AiServer: Sent providers: ', providers toString.
@@ -83,40 +82,29 @@ Example request:
8382
Example result:
8483
{ success: true, text: 'This is a test.' }"
8584

86-
onChat: request response: response
87-
| chatResponse chatRequest |
85+
async onChat: request response: response
86+
| chatResponse chatRequest provider ai text |
8887

8988
chatResponse := AiChatResponse new success: false; text: ''.
9089

9190
chatRequest := AiChatRequest fromObject: request query.
9291
self log: 'AiServer: Received chat request: ', chatRequest toString.
9392

94-
chatRequest provider isNil
95-
ifTrue: [ response send: ( chatResponse text: 'Chat request parameter "provider" missing' ) ]
96-
ifFalse: [
97-
chatRequest model isNil
98-
ifTrue: [ response send: ( chatResponse text: 'Chat request parameter "model" missing' ) ]
99-
ifFalse: [
100-
chatRequest messages isNil
101-
ifTrue: [ response send: ( chatResponse text: 'Chat request parameter "messages" missing' ) ]
102-
ifFalse: [ self onChat2: chatRequest response: response ] ] ].
103-
!
104-
onChat2: chatRequest response: response
105-
| provider ai |
93+
chatRequest provider ifNil: [
94+
^ response send: ( chatResponse text: 'Chat request parameter "provider" missing' ) ].
95+
chatRequest model ifNil: [
96+
^ response send: ( chatResponse text: 'Chat request parameter "model" missing' ) ].
97+
chatRequest messages ifNil: [
98+
^ response send: ( chatResponse text: 'Chat request parameter "messages" missing' ) ].
10699

107100
provider := chatRequest provider toLowerCase.
108101
ai := aiMap get: provider.
109-
ai isNil
110-
ifTrue: [ response send: ( AiChatResponse success: false text: 'AI provider not available: ', provider ) ]
111-
ifFalse: [ ai chat: chatRequest messages
112-
then: [ :text | self onChat3: text response: response ] ].
113-
!
114-
onChat3: text response: response
115-
| chatResponse |
102+
ai ifNil: [
103+
^ response send: ( chatResponse text: 'AI provider not available: ', provider ) ].
116104

117-
chatResponse := AiChatResponse new success: true; text: text.
105+
text := await ai chat: chatRequest messages.
106+
chatResponse success: true; text: text.
118107
response send: chatResponse.
119-
120108
self log: 'AiServer: Sent chat response: ', chatResponse toString.
121109
!
122110
stop

Examples/AI/Server/src/types.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,34 @@
22
// This is done to facilitate inspecting their TS types in VSCode.
33
// This file is not used when running this app.
44

5-
// Files
6-
import * as fs$ from "fs";
7-
import * as path$ from "path";
8-
9-
// HTTP
10-
import http from "http";
11-
import { createHttpTerminator } from "http-terminator";
12-
13-
// Express
14-
import express from "express";
15-
import cors from "express";
16-
import session from "express-session";
17-
185
// AI - Ollama
19-
import { Ollama, ChatRequest, ChatResponse, Message as OllamaMessage } from 'ollama';
6+
import * as ollama from "ollama";
7+
let olOllama: ollama.Ollama;
8+
let olChatRequest: ollama.ChatRequest;
9+
let olChatResponse: ollama.ChatResponse;
10+
let olMessage: ollama.Message;
2011

2112
// AI - OpenAI
22-
import OpenAI from "openai";
23-
import { ChatCompletion } from "openai/resources/chat/completions.js";
24-
type ChatCompletionChoice = ChatCompletion.Choice;
25-
import { ChatCompletionMessage } from "openai/resources/chat/completions.js";
26-
import { CompletionUsage } from "openai/resources/completions.js";
27-
let completionTokensDetails: CompletionUsage.CompletionTokensDetails;
28-
let promptTokensDetails: CompletionUsage.PromptTokensDetails;
13+
import Openai from "openai";
14+
let oaiChatCompletion: Openai.ChatCompletion;
15+
let oaiChatCompletionChoice: Openai.ChatCompletion.Choice;
16+
let oaiChatCompletionMessage: Openai.ChatCompletionMessage;
17+
let oaiChatCompletionUsage: Openai.CompletionUsage;
18+
let oaiCompletionTokensDetails: Openai.CompletionUsage.CompletionTokensDetails;
19+
let oaiPromptTokensDetails: Openai.CompletionUsage.PromptTokensDetails;
2920

3021
// AI - Google AI
31-
import { GoogleGenerativeAI, ModelParams, GenerativeModel,
32-
GenerateContentResult, GenerateContentResponse } from "@google/generative-ai";
22+
import * as googleai from "@google/generative-ai";
23+
let gaiGoogleAi: googleai.GoogleGenerativeAI;
24+
let gaiModelParams: googleai.ModelParams;
25+
let gaiGenerativeModel: googleai.GenerativeModel;
26+
let gaiGenerateContentResult: googleai.GenerateContentResult;
27+
let gaiGenerateContentResponse: googleai.GenerateContentResponse;
3328

3429
// AI - Anthropic
35-
import { Anthropic, ClientOptions } from '@anthropic-ai/sdk';
30+
import * as anthropic from "@anthropic-ai/sdk";
31+
let antAnthropic: anthropic.Anthropic;
32+
let antClientOptions: anthropic.ClientOptions;
3633
import { MessageCreateParams } from '@anthropic-ai/sdk/resources/index.mjs';
37-
import { Message, TextBlock } from '@anthropic-ai/sdk/resources/index.mjs';
38-
34+
import { Message } from '@anthropic-ai/sdk/resources/index.mjs';
35+
import { TextBlock } from '@anthropic-ai/sdk/resources/index.mjs';

Smalltalk/AI/Node/Anthropic/Anthropic.st

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ METHODS
2626

2727
"Chat"
2828

29-
chat: messages then: block
30-
| messageParams createMessageParams |
29+
async chat: messages
30+
| messageParams createMessageParams message |
3131

3232
messageParams := messages map: [ :message |
3333
AnthropicMessageParam new
@@ -39,15 +39,11 @@ chat: messages then: block
3939
maxTokens: 1024;
4040
messages: messageParams.
4141

42-
self create: createMessageParams
43-
then: [ :message | self onChat: message then: block ].
42+
message := await self create: createMessageParams.
43+
^ message content first text.
4444
!
45-
onChat: message then: block
46-
block value: message content first text.
47-
!
48-
create: params then: block
49-
INLINE 'this.js.messages.create( params.js )
50-
.then( message => block.$value$( stAnthropicMessage$class.$fromJs$( message ) ) )'.
45+
async create: params
46+
^ AnthropicMessage fromJs: INLINE 'await this.js.messages.create( params.js )'.
5147
!
5248

5349
"Options set"

Smalltalk/AI/Node/Anthropic/Test/TestAnthropic.st

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ CLASS TestAnthropic EXTENDS Test MODULE TestAi CLASSVARS '' VARS 'anthropic'
55
disabled
66
^ Anthropic available not.
77
!
8-
test
9-
| messageParam createMessageParams |
8+
async test
9+
| messageParam createMessageParams message textBlock usage |
1010

1111
anthropic := Anthropic new.
1212
self assert: [ anthropic apiKey startsWith: 'sk-ant' ].
@@ -17,9 +17,9 @@ test
1717

1818
messageParam := AnthropicMessageParam new
1919
role: 'user';
20-
content: 'Say this is a test'.
20+
content: 'Say exactly: This is a test'.
2121
self assert: [ messageParam role = 'user' ].
22-
self assert: [ messageParam content = 'Say this is a test' ].
22+
self assert: [ messageParam content = 'Say exactly: This is a test' ].
2323

2424
createMessageParams := AnthropicCreateMessageParams new
2525
model: anthropic model;
@@ -31,14 +31,9 @@ test
3131

3232
messageParam := createMessageParams messages first.
3333
self assert: [ messageParam role = 'user' ].
34-
self assert: [ messageParam content = 'Say this is a test' ].
35-
36-
anthropic create: createMessageParams
37-
then: [ :message | self onCreate: message ].
38-
!
39-
onCreate: message
40-
| textBlock usage |
34+
self assert: [ messageParam content = 'Say exactly: This is a test' ].
4135

36+
message := await anthropic create: createMessageParams.
4237
self assert: [ message class = AnthropicMessage ].
4338
self assert: [ message content length = 1 ].
4439
self assert: [ message id startsWith: 'msg' ].

Smalltalk/AI/Node/Deepseek/Test/TestDeepseek.st

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,14 @@ The class DeepseekClientOptions uses the Deepseek base URL and API key env vars
1515
disabled
1616
^ Deepseek available not.
1717
!
18-
test
19-
| deepseek request |
18+
async test
19+
| deepseek request chatCompletion choice message usage |
2020

2121
deepseek := Deepseek new.
22-
2322
request := OpenaiChatCompletionRequest new
2423
model: deepseek model;
25-
addRole: 'user' content: 'Say this is a test'.
26-
27-
deepseek createChatCompletion: request
28-
then: [ :chatCompletion | self onChatCompletion: chatCompletion ].
29-
!
30-
onChatCompletion: chatCompletion
31-
| choice message usage |
24+
addRole: 'user' content: 'Say exactly: This is a test'.
25+
chatCompletion := await deepseek createChatCompletion: request.
3226

3327
self assert: [ chatCompletion class = OpenaiChatCompletion ].
3428
self assert: [ ( Date new toSeconds - chatCompletion created toSeconds ) < 60 ].

Smalltalk/AI/Node/Googleai/Googleai.st

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ generativeModel: params
2929

3030
"Chat"
3131

32-
chat: messages then: block
33-
| params generativeModel |
32+
async chat: messages
33+
| params generativeModel response |
3434

3535
params := GoogleaiModelParams new model: self model.
3636
generativeModel := self generativeModel: params.
37-
generativeModel generateContent: messages
38-
then: [ :response | block value: response text ].
37+
response := await generativeModel generateContent: messages.
38+
^ response text.
3939
!

Smalltalk/AI/Node/Googleai/GoogleaiModel.st

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ model
1313

1414
"Content"
1515

16-
generateContent: messages then: block
16+
async generateContent: messages
1717
"This evaluates block with a ContentResponse.
1818
ContentResult is skipped because it only has the one reponse member."
19-
INLINE 'this.js.generateContent( messages.$toJs() )
20-
.then( result => block.$value$( stGoogleaiContentResponse$class.$fromJs$( result.response ) ) )'.
19+
^ GoogleaiContentResponse fromJs: INLINE '( await this.js.generateContent( messages.$toJs() ) ).response'.
2120
!
22-

Smalltalk/AI/Node/Googleai/Test/TestGoogleai.st

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ CLASS TestGoogleai EXTENDS Test MODULE TestAi CLASSVARS '' VARS ''
55
disabled
66
^ Googleai available not.
77
!
8-
test
9-
| googleai params model |
8+
async test
9+
| googleai params model response text |
1010

1111
googleai := Googleai new.
1212
self assert: [ googleai apiKey length > 10 ].
@@ -18,11 +18,7 @@ test
1818
self assert: [ model apiKey = googleai apiKey ].
1919
self assert: [ model model includes: params model ].
2020

21-
model generateContent: #( 'Say exactly: This is a test' )
22-
then: [ :response | self onGenerateContent: response ].
23-
!
24-
onGenerateContent: response
25-
| text |
21+
response := await model generateContent: #( 'Say exactly: This is a test' ).
2622
text := response text.
2723
self assert: [ text toLowerCase includes: 'test' ].
2824
!

Smalltalk/AI/Node/Ollama/Ollama.st

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,18 @@ METHODS
1515

1616
"Chat"
1717

18-
chat: messages then: block
19-
| request |
18+
async chat: messages
19+
| request response |
2020
request := OllamaChatRequest new
2121
model: self model.
2222
messages do: [ :message |
2323
request addRole: 'user' content: message ].
2424

25-
self chatRequest: request
26-
then: [ :response | self onChat: response then: block ].
25+
response := await self chatRequest: request.
26+
^ response message content.
2727
!
28-
onChat: response then: block
29-
block value: response message content.
30-
!
31-
chatRequest: request then: block
32-
INLINE 'this.js.chat( request.js )
33-
.then( response => block.$value$( stOllamaChatResponse$class.$fromJs$( response ) ) )'.
28+
async chatRequest: request
29+
^ OllamaChatResponse fromJs: INLINE 'await this.js.chat( request.js )'.
3430
!
3531

3632
"Accessing"

0 commit comments

Comments
 (0)