Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: studio/trace #139

Closed
wants to merge 14 commits into from
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package com.alibaba.cloud.ai.dashscope.chat;

import java.util.ArrayList;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletion;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionChunk;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionFinishReason;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionMessage;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionMessage.ChatCompletionFunction;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionMessage.MediaContent;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionMessage.ToolCall;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionOutput;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionOutput.Choice;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionRequest;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionRequestInput;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionRequestParameter;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.FunctionTool;
import com.alibaba.cloud.ai.dashscope.chat.observation.DashScopeChatModelObservationConvention;
import com.alibaba.cloud.ai.dashscope.metadata.DashScopeAiUsage;
import com.alibaba.cloud.ai.observation.conventions.AiProvider;
Expand All @@ -17,24 +22,20 @@
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.model.*;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.observation.ChatModelObservationContext;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.chat.observation.ChatModelObservationDocumentation;
import reactor.core.publisher.Flux;

import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.*;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionMessage.*;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi.ChatCompletionOutput.Choice;
import reactor.core.publisher.Mono;

import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.messages.ToolResponseMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
import org.springframework.ai.chat.metadata.ChatResponseMetadata;
import org.springframework.ai.chat.model.AbstractToolCallSupport;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.model.MessageAggregator;
import org.springframework.ai.chat.observation.ChatModelObservationContext;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.chat.observation.ChatModelObservationDocumentation;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.ModelOptionsUtils;
Expand All @@ -45,6 +46,16 @@
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MimeType;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
* {@link ChatModel} implementation for {@literal Alibaba DashScope} backed by
Expand Down
13 changes: 12 additions & 1 deletion spring-ai-alibaba-examples/cli-debug-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version>

<!-- Spring AI -->
<spring-ai-alibaba.version>1.0.0-M3.2</spring-ai-alibaba.version>
<spring-ai-alibaba.version>1.0.0-M3.workflow-SNAPSHOT</spring-ai-alibaba.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -65,4 +65,15 @@
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

</project>
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.alibaba.cloud.ai.example.cli.clidebugexample;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan({"com.alibaba.cloud.ai"})
@SpringBootApplication
@MapperScan("com.alibaba.cloud.ai.mapper")
public class CliDebugExampleApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
spring:
application:
name: cli-debug-example

ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
datasource:
url: jdbc:sqlite:spring-ai-alibaba-studio/db/studio.db
driver-class-name: org.sqlite.JDBC



mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
cache-enabled: false
map-underscore-to-camel-case: true

server:
port: 8080
6 changes: 6 additions & 0 deletions spring-ai-alibaba-starter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
<artifactId>spring-ai-alibaba-studio</artifactId>
<version>${project.parent.version}</version>
</dependency>

<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-studio</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>

</project>
Binary file added spring-ai-alibaba-studio/db/studio.db
Binary file not shown.
30 changes: 30 additions & 0 deletions spring-ai-alibaba-studio/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,36 @@
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc-openapi.version}</version>
</dependency>

<!-- OpenTelemetry API -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>


<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
</dependency>

<!--mybatis-plus插件-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.9</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.alibaba.cloud.ai.config;

import com.alibaba.cloud.ai.observation.AlibabaObservationHandler;
import com.alibaba.cloud.ai.observation.handler.ContextHandlerFactory;
import com.alibaba.cloud.ai.service.impl.ObservationDetailServiceImpl;
import com.alibaba.cloud.ai.service.impl.ObservationServiceImpl;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ObservationConfig {

@Bean
public ObservationRegistry observationRegistry(ContextHandlerFactory contextHandlerFactory) {
ObservationRegistry observationRegistry = ObservationRegistry.create();
observationRegistry.observationConfig()
.observationHandler(new AlibabaObservationHandler(contextHandlerFactory));
return observationRegistry;
}

@Bean
public ContextHandlerFactory contextHandlerFactory(ObservationServiceImpl observationService,
ObservationDetailServiceImpl modelObservationDetailService) {
return new ContextHandlerFactory(observationService, modelObservationDetailService);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.alibaba.cloud.ai.controller;

import com.alibaba.cloud.ai.common.R;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.entity.ChatDTO;
import com.alibaba.cloud.ai.entity.ObservationDetailEntity;
import com.alibaba.cloud.ai.entity.ObservationEntity;
import com.alibaba.cloud.ai.service.impl.ObservationDetailServiceImpl;
import com.alibaba.cloud.ai.service.impl.ObservationServiceImpl;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.MediaType;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
* @Description:
* @Author: XiaoYunTao
* @Date: 2024/11/19
*/
@CrossOrigin
@RestController
@RequestMapping("studio/api/observation")
public class ObservationApiController {

private final ObservationServiceImpl observationServiceImpl;

private final ObservationDetailServiceImpl observationDetailServiceImpl;

private final ChatClient chatClient;

private final DashScopeChatModel dashScopeChatModel;

public ObservationApiController(ObservationServiceImpl observationServiceImpl,
ObservationDetailServiceImpl observationDetailServiceImpl, ObservationRegistry observationRegistry,
DashScopeApi dashScopeApi, ChatClient.Builder builder) {
this.observationServiceImpl = observationServiceImpl;
this.observationDetailServiceImpl = observationDetailServiceImpl;
this.dashScopeChatModel = new DashScopeChatModel(dashScopeApi,
DashScopeChatOptions.builder().withModel(DashScopeApi.DEFAULT_CHAT_MODEL).withTemperature(0.7d).build(),
null, new RetryTemplate(), observationRegistry);
this.chatClient = ChatClient.create(dashScopeChatModel, observationRegistry);
// this.chatClient = builder.build();
}

@GetMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE)
public R<List<ObservationEntity>> list() {
List<ObservationEntity> list = observationServiceImpl.list();
return R.success(list);
}

@GetMapping(value = "detail/list", produces = MediaType.APPLICATION_JSON_VALUE)
public R<List<ObservationDetailEntity>> detailList() {
List<ObservationDetailEntity> list = observationDetailServiceImpl.list();
return R.success(list);
}

/**
* 直接对话接口
* @param chatDTO
* @return
*/
@PostMapping(value = "generate", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public R<String> generate(@RequestBody ChatDTO chatDTO) {
String call = chatClient.prompt(chatDTO.getMessage()).call().content();
return R.success(call);
}

@GetMapping(value = "exportObservation", produces = MediaType.APPLICATION_JSON_VALUE)
public R<List<ObservationDetailEntity>> exportObservation() {
observationServiceImpl.exportObservation();
return R.success(null);
}

@GetMapping(value = "exportObservationDetail", produces = MediaType.APPLICATION_JSON_VALUE)
public R<List<ObservationDetailEntity>> exportObservationDetail() {
observationDetailServiceImpl.exportObservationDetail();
return R.success(null);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.alibaba.cloud.ai.entity;

import lombok.Getter;

/**
* @Description:
* @Author: XiaoYunTao
* @Date: 2024/9/9
*/
@Getter
public class ChatDTO {

String message;

String userId;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.alibaba.cloud.ai.entity;

import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
* @Description:
* @Author: XiaoYunTao
* @Date: 2024/11/18
*/
@Data
@TableName("tb_observation_detail")
public class ObservationDetailEntity {

@TableId(value = "id", type = IdType.ASSIGN_ID)
@ExcelProperty("id")
private String id;

@ExcelProperty("modelObservationId")
private String modelObservationId;

@ExcelProperty("highCardinalityKeyValues")
private String highCardinalityKeyValues;

@ExcelProperty("lowCardinalityKeyValues")
private String lowCardinalityKeyValues;

@ExcelProperty("operationMetadata")
private String operationMetadata;

@ExcelProperty("request")
private String request;

@ExcelProperty("response")
private String response;

@ExcelProperty("contextualName")
private String contextualName;

@ExcelProperty("addTime")
private Long addTime;

}
Loading