Skip to content

Commit 3910c8a

Browse files
committed
feat: iOS sample integration
1 parent 9310e86 commit 3910c8a

File tree

16 files changed

+243
-18
lines changed

16 files changed

+243
-18
lines changed

sample/android/src/main/java/co/yml/ychat/android/MainViewModel.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ class MainViewModel(private val chatGpt: YChat) : ViewModel() {
2323

2424
private val imageGenerations by lazy {
2525
chatGpt.imageGenerations()
26-
.setResults(2)
2726
}
2827

2928
private val _items = mutableStateListOf<MessageItem>()

sample/android/src/main/java/co/yml/ychat/android/ui/SendMessageLayout.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ fun SendMessageLayout() {
5353
val viewModel = koinViewModel<MainViewModel>()
5454
val isLoading: Boolean by viewModel.isLoading.observeAsState(initial = false)
5555

56-
5756
Row(
5857
modifier = Modifier
5958
.background(color = MaterialTheme.colors.background)

sample/ios/YChatApp/Features/Completion/CompletionView.swift

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,14 @@ private extension CompletionView {
7272
}
7373
case .bot:
7474
HStack {
75-
botChatBubble(message: chatMessage.message)
76-
Spacer().frame(width: 60)
77-
Spacer()
75+
if let imageUrl = chatMessage.url {
76+
botImageBubble(imageUrl)
77+
Spacer()
78+
} else {
79+
botChatBubble(message: chatMessage.message)
80+
Spacer().frame(width: 60)
81+
Spacer()
82+
}
7883
}
7984
case .loading:
8085
HStack {
@@ -120,6 +125,28 @@ private extension CompletionView {
120125
.cornerRadius(16, corners: [.bottomLeft, .bottomLeft, .topRight])
121126
}
122127
}
128+
129+
@ViewBuilder
130+
private func botImageBubble(_ url: String) -> some View {
131+
HStack(alignment: .top, spacing: 4) {
132+
Circle()
133+
.fill(.green)
134+
.frame(width: 40, height: 40)
135+
.overlay {
136+
Image(uiImage: Icon.bot.uiImage)
137+
.renderingMode(.template)
138+
.foregroundColor(.white)
139+
}
140+
ZStack {
141+
AsyncImage(url: URL(string: url))
142+
.foregroundColor(.grayDark)
143+
}
144+
.padding(.horizontal, 16)
145+
.padding(.vertical, 8)
146+
.background(Color.grayLight)
147+
.cornerRadius(16, corners: [.bottomLeft, .bottomLeft, .topRight])
148+
}
149+
}
123150

124151
@ViewBuilder
125152
private func sendMessageSection() -> some View {

sample/ios/YChatApp/Features/Completion/Model/ChatMessage.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct ChatMessage: Identifiable, Equatable {
1212
let id: String
1313
var message: String = ""
1414
var type: MessageType = .human(error: false)
15+
var url: String?
1516

1617
enum MessageType: Equatable {
1718
case human(error: Bool), bot, loading

sample/ios/YChatApp/Features/Completion/ViewModel/CompletionViewModel.swift

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ internal final class CompletionViewModel: ObservableObject {
1919
content: "You are a helpful assistant."
2020
)
2121

22+
private var imageGenerations: ImageGenerations =
23+
YChatCompanion.shared.create(apiKey: Config.apiKey)
24+
.imageGenerations()
25+
2226
@Published
2327
var message: String = ""
2428

@@ -37,9 +41,15 @@ internal final class CompletionViewModel: ObservableObject {
3741
cleanLastMessage()
3842
addLoading()
3943
do {
40-
let result = try await chatCompletions.execute(content: input)[0].content
41-
removeLoading()
42-
addAIMessage(message: result)
44+
if input.contains("/image ") {
45+
let result = try await imageGenerations.execute(prompt: input)[0].url
46+
removeLoading()
47+
addAIImage(url: result)
48+
} else {
49+
let result = try await chatCompletions.execute(content: input)[0].content
50+
removeLoading()
51+
addAIMessage(message: result)
52+
}
4353
} catch {
4454
removeLoading()
4555
setError()
@@ -64,6 +74,15 @@ internal final class CompletionViewModel: ObservableObject {
6474
)
6575
chatMessageList.append(chatMessage)
6676
}
77+
78+
private func addAIImage(url: String) {
79+
let chatMessage = ChatMessage(
80+
id: UUID().uuidString,
81+
type: .bot,
82+
url: url
83+
)
84+
chatMessageList.append(chatMessage)
85+
}
6786

6887
private func addLoading() {
6988
let chatMessage = ChatMessage(

sample/jvm/src/main/java/co/yml/ychat/jvm/controller/YChatController.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ public ResponseEntity<String> chatCompletions(
3232
return ResponseEntity.ok(result);
3333
}
3434

35+
@GetMapping("generations")
36+
public ResponseEntity<String> imageGenerations(
37+
@RequestParam(value = "prompt", defaultValue = Defaults.CHAT_COMPLETION_INPUT) String input
38+
) throws Exception {
39+
String result = YChatService.getImageGenerationsAnswer(input);
40+
return ResponseEntity.ok(result);
41+
}
42+
3543
private static class Defaults {
3644
static final String COMPLETION_INPUT = "Say this is a test.";
3745
static final String CHAT_COMPLETION_INPUT = "Tell me one strength exercise";

sample/jvm/src/main/java/co/yml/ychat/jvm/services/YChatService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.springframework.stereotype.Service;
88
import java.util.concurrent.CompletableFuture;
99
import co.yml.ychat.YChat;
10+
import co.yml.ychat.domain.model.ImageGenerated;
1011

1112
@Service
1213
public class YChatService {
@@ -35,6 +36,13 @@ public String getChatCompletionsAnswer(String input, String topic) throws Except
3536
return future.get().get(0).getContent();
3637
}
3738

39+
public String getImageGenerationsAnswer(String prompt) throws Exception {
40+
final CompletableFuture<List<String>> future = new CompletableFuture<>();
41+
ychat.imageGenerations()
42+
.execute(prompt, new CompletionCallbackResult<>(future));
43+
return future.get().get(0);
44+
}
45+
3846
private static class CompletionCallbackResult<T> implements YChat.Callback<T> {
3947

4048
private final CompletableFuture<T> future;

ychat/src/commonMain/kotlin/co/yml/ychat/domain/mapper/ImageGenerationsMapper.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ internal fun ImageGenerationsDto.toImageGenerated(): List<ImageGenerated> {
1111
}
1212
}
1313

14-
1514
internal fun ImageGenerationsParams.toImageGenerationsParamsDto(): ImageGenerationsParamsDto {
1615
return ImageGenerationsParamsDto(
1716
prompt = this.prompt,

ychat/src/commonMain/kotlin/co/yml/ychat/domain/model/ImageGenerated.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import kotlinx.serialization.SerialName
44
import kotlinx.serialization.Serializable
55

66
/**
7-
* Represents a message in a conversation, consisting of a [role] indicating the speaker
8-
* (e.g., “system”, “user” or “assistant”), and the [content] of the message sent by the speaker.
9-
* @property role The role of the speaker who sends the message.
10-
* @property content The content of the message sent by the speaker.
7+
* Represents a image generated by a prompt, consisting of a [url] generated by the system (AI).
8+
* @property url The url of the image generated by the input provided.
119
*/
1210
@Serializable
1311
data class ImageGenerated(

ychat/src/commonMain/kotlin/co/yml/ychat/domain/model/ImageGenerationsParams.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
package co.yml.ychat.domain.model
22

3+
/**
4+
* Parameters to configure the Image Generations API.
5+
*
6+
* @param prompt The prompt(s) to generate images for.
7+
*
8+
* @param results: Quantity of images to be generated.
9+
*
10+
* @param size: The size of the images generated (squared). Ex. 256x256, 512x512, 1024x1024
11+
*
12+
* @param responseFormat: The format in which the generated images are returned. Must be one of url or b64_json.
13+
*
14+
* @param user: A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
15+
*/
316
internal data class ImageGenerationsParams(
417
var prompt: String = "",
5-
var results: Int = 2,
18+
var results: Int = 1,
619
var size: String = "256x256",
720
var responseFormat: String = "url",
821
var user: String = "",

0 commit comments

Comments
 (0)