mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-12-04 21:18:22 +08:00
[Core] Refactor chat (#392)
This commit is contained in:
commit
711cf3e3c8
@ -18,18 +18,18 @@ spring.resources.add-mappings=false
|
||||
spring.web.resources.add-mappings=true
|
||||
|
||||
################################ Database configure #################################
|
||||
### The system uses h2 storage by default, and the following related configurations can be modified
|
||||
#spring.datasource.driverClassName=org.h2.Driver
|
||||
#spring.datasource.url=jdbc:h2:mem:datacap
|
||||
#spring.datasource.username=h2
|
||||
#spring.datasource.password=h2
|
||||
#spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
#spring.h2.console.enabled=true
|
||||
## The system uses h2 storage by default, and the following related configurations can be modified
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.datasource.url=jdbc:h2:mem:datacap
|
||||
spring.datasource.username=h2
|
||||
spring.datasource.password=h2
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
spring.h2.console.enabled=true
|
||||
|
||||
### If you enable MySQL storage, please modify the following configuration
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/datacap?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&useOldAliasMetadataBehavior=true&jdbcCompliantTruncation=false
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=12345678
|
||||
#spring.datasource.url=jdbc:mysql://localhost:3306/datacap?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&useOldAliasMetadataBehavior=true&jdbcCompliantTruncation=false
|
||||
#spring.datasource.username=root
|
||||
#spring.datasource.password=12345678
|
||||
|
||||
################################ Redis configure #################################
|
||||
### Set redis environment
|
||||
|
@ -0,0 +1,51 @@
|
||||
package io.edurt.datacap.server.controller;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.body.FilterBody;
|
||||
import io.edurt.datacap.service.service.BaseService;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
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.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public abstract class BaseController<T>
|
||||
implements Serializable
|
||||
{
|
||||
private final PagingAndSortingRepository repository;
|
||||
private final BaseService<T> service;
|
||||
|
||||
protected BaseController(PagingAndSortingRepository repository, BaseService<T> service)
|
||||
{
|
||||
this.repository = repository;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data based on pagination
|
||||
*/
|
||||
@PostMapping(value = "list")
|
||||
public CommonResponse list(@RequestBody FilterBody filter)
|
||||
{
|
||||
return service.getAll(repository, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save changes
|
||||
*/
|
||||
@RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT})
|
||||
public CommonResponse saveAndUpdate(@RequestBody T configure)
|
||||
{
|
||||
return service.saveOrUpdate(repository, configure);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public CommonResponse delete(@RequestParam(value = "id") Long id)
|
||||
{
|
||||
return service.deleteById(repository, id);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package io.edurt.datacap.server.controller;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.body.FilterBody;
|
||||
import io.edurt.datacap.service.entity.ChatEntity;
|
||||
import io.edurt.datacap.service.entity.MessageEntity;
|
||||
import io.edurt.datacap.service.repository.ChatRepository;
|
||||
import io.edurt.datacap.service.service.ChatService;
|
||||
import io.edurt.datacap.service.service.MessageService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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;
|
||||
|
||||
@RestController()
|
||||
@RequestMapping(value = "/api/v1/chat")
|
||||
public class ChatController
|
||||
extends BaseController<ChatEntity>
|
||||
{
|
||||
private final ChatRepository repository;
|
||||
private final ChatService service;
|
||||
private final MessageService messageService;
|
||||
|
||||
public ChatController(ChatRepository repository, ChatService service, MessageService messageService)
|
||||
{
|
||||
super(repository, service);
|
||||
this.repository = repository;
|
||||
this.service = service;
|
||||
this.messageService = messageService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse list(@RequestBody FilterBody filter)
|
||||
{
|
||||
return this.service.getAllByUser(filter);
|
||||
}
|
||||
|
||||
@GetMapping(value = "{id}/messages")
|
||||
public CommonResponse<List<MessageEntity>> getMessagesByChat(@PathVariable(value = "id") Long id)
|
||||
{
|
||||
return this.messageService.getMessageByChatAndUser(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package io.edurt.datacap.server.controller;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.body.UserQuestionBody;
|
||||
import io.edurt.datacap.service.entity.MessageEntity;
|
||||
import io.edurt.datacap.service.repository.MessageRepository;
|
||||
import io.edurt.datacap.service.service.MessageService;
|
||||
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;
|
||||
|
||||
@RestController()
|
||||
@RequestMapping(value = "/api/v1/message")
|
||||
public class MessageController
|
||||
extends BaseController<MessageEntity>
|
||||
{
|
||||
private final MessageRepository repository;
|
||||
private final MessageService service;
|
||||
|
||||
public MessageController(MessageRepository repository, MessageService service)
|
||||
{
|
||||
super(repository, service);
|
||||
this.repository = repository;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@PostMapping(value = "ai/reply")
|
||||
public CommonResponse<MessageEntity> aiReply(@RequestBody UserQuestionBody configure)
|
||||
{
|
||||
return this.service.aiReply(configure);
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.body.FilterBody;
|
||||
import io.edurt.datacap.service.body.UserNameBody;
|
||||
import io.edurt.datacap.service.body.UserPasswordBody;
|
||||
import io.edurt.datacap.service.body.UserQuestionBody;
|
||||
import io.edurt.datacap.service.body.user.UserRole;
|
||||
import io.edurt.datacap.service.entity.PageEntity;
|
||||
import io.edurt.datacap.service.entity.RoleEntity;
|
||||
@ -74,12 +73,6 @@ public class UserController
|
||||
return this.userLogService.getAllByFilter(filter);
|
||||
}
|
||||
|
||||
@PostMapping(value = "startChat")
|
||||
public CommonResponse<Object> startChat(@RequestBody UserQuestionBody configure)
|
||||
{
|
||||
return this.userService.startChat(configure);
|
||||
}
|
||||
|
||||
@GetMapping(value = "sugs/{id}")
|
||||
public CommonResponse<List<Object>> getSugs(@PathVariable Long id)
|
||||
{
|
||||
|
@ -488,3 +488,5 @@ values ('2', '7'),
|
||||
-- --------------------------------
|
||||
alter table `menus`
|
||||
add column `redirect` bigint default 0;
|
||||
ALTER TABLE `menus`
|
||||
ADD COLUMN `is_new` BOOLEAN DEFAULT FALSE;
|
||||
|
@ -217,22 +217,6 @@ OFFSET ${page:Integer}', 'Get all data from table by limited', 'MySQL,ClickHouse
|
||||
, '[{"column":"table","type":"String","expression":"${table:String}"},{"column":"size","type":"Integer","expression":"${size:Integer}"},{"column":"page","type":"Integer","expression":"${page:Integer}"}]'
|
||||
, '2023-01-10 13:31:10', '2023-01-10 13:31:10', 0);
|
||||
-- --------------------------------
|
||||
-- Table structure for user_chat
|
||||
-- --------------------------------
|
||||
CREATE TABLE IF NOT EXISTS user_chat
|
||||
(
|
||||
id int PRIMARY KEY AUTO_INCREMENT,
|
||||
name varchar(255) NOT NULL,
|
||||
question text NOT NULL,
|
||||
answer text NULL,
|
||||
type varchar(100) NULL,
|
||||
create_time date NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
end_time date NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
elapsed bigint NULL,
|
||||
user_id int NOT NULL,
|
||||
is_new boolean NULL DEFAULT 1
|
||||
);
|
||||
-- --------------------------------
|
||||
-- Table structure for user_log
|
||||
-- --------------------------------
|
||||
CREATE TABLE IF NOT EXISTS user_log
|
||||
@ -263,22 +247,25 @@ VALUES (2, 2);
|
||||
-- --------------------------------
|
||||
-- Table structure for users
|
||||
-- --------------------------------
|
||||
CREATE TABLE IF NOT EXISTS users
|
||||
CREATE TABLE IF NOT EXISTS datacap_user
|
||||
(
|
||||
id bigint PRIMARY KEY AUTO_INCREMENT,
|
||||
username varchar(255) NULL COMMENT ' ',
|
||||
password varchar(255) NULL COMMENT ' ',
|
||||
create_time date NULL DEFAULT CURRENT_TIMESTAMP(5),
|
||||
third_configure text NULL
|
||||
chat_configure text NULL
|
||||
);
|
||||
TRUNCATE TABLE users;
|
||||
ALTER TABLE users
|
||||
TRUNCATE TABLE datacap_user;
|
||||
ALTER TABLE datacap_user
|
||||
ALTER COLUMN id RESTART WITH 1;
|
||||
INSERT INTO users (username, password)
|
||||
ALTER TABLE datacap_user
|
||||
ADD COLUMN `is_system` BOOLEAN DEFAULT FALSE;
|
||||
INSERT INTO datacap_user (username, password)
|
||||
VALUES ('admin', '$2a$10$ee2yg.Te14GpHppDUROAi.HzYR5Q.q2/5vrZvAr4TFY3J2iT663JG');
|
||||
INSERT INTO users (username, password)
|
||||
INSERT INTO datacap_user (username, password)
|
||||
VALUES ('datacap', '$2a$10$bZ4XBRlYUjKfkBovWT9TuuXlEF7lpRxVrXS8iqyCjCHUqy4RPTL8.');
|
||||
|
||||
INSERT INTO datacap_user(username, is_system)
|
||||
VALUES ('Ai', TRUE);
|
||||
-- --------------------------------
|
||||
-- Update to 1.11.0 --
|
||||
-- --------------------------------
|
||||
@ -305,3 +292,50 @@ WHERE
|
||||
keyspace_name = ''${database:String}''
|
||||
and table_name = ''${table:String}''', 'Get the data column from the database and table', 'Cassandra',
|
||||
'[{"column":"database","type":"String","expression":"${database:String}"},{"column":"table","type":"String","expression":"${table:String}"}]', 1);
|
||||
|
||||
-- --------------------------------
|
||||
-- Update to 1.12.0 --
|
||||
-- --------------------------------
|
||||
CREATE TABLE `datacap_chat`
|
||||
(
|
||||
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`active` BOOLEAN DEFAULT TRUE,
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`avatar` VARCHAR(255) DEFAULT NULL,
|
||||
`description` VARCHAR(255) DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_chat_user_relation`
|
||||
(
|
||||
chat_id BIGINT,
|
||||
user_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message`
|
||||
(
|
||||
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`active` BOOLEAN DEFAULT TRUE,
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`content` TEXT DEFAULT NULL,
|
||||
`model` VARCHAR(255) DEFAULT NULL,
|
||||
`type` VARCHAR(100),
|
||||
`prompt_tokens` BIGINT DEFAULT 0,
|
||||
`completion_tokens` BIGINT DEFAULT 0,
|
||||
`total_tokens` BIGINT DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message_user_relation`
|
||||
(
|
||||
message_id BIGINT,
|
||||
user_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message_chat_relation`
|
||||
(
|
||||
message_id BIGINT,
|
||||
chat_id BIGINT
|
||||
);
|
||||
|
@ -1,12 +1,58 @@
|
||||
-- --------------------------------
|
||||
-- Update to 1.12.0 --
|
||||
-- --------------------------------
|
||||
alter table `menus`
|
||||
add column `redirect` bigint default 0,
|
||||
add column `is_new` boolean default false;
|
||||
ALTER TABLE `menus`
|
||||
ADD COLUMN `redirect` BIGINT DEFAULT 0,
|
||||
ADD COLUMN `is_new` BOOLEAN DEFAULT FALSE;
|
||||
|
||||
alter table `user_chat`
|
||||
add column `model` varchar(30) default 'gpt-3.5-turbo-0613',
|
||||
add column `prompt_tokens` bigint default 0,
|
||||
add column `completion_tokens` bigint default 0,
|
||||
add column `total_tokens` bigint default 0;
|
||||
RENAME TABLE `users` TO `datacap_user`;
|
||||
|
||||
ALTER TABLE `datacap_user`
|
||||
ADD COLUMN `is_system` BOOLEAN DEFAULT FALSE;
|
||||
|
||||
INSERT INTO `datacap_user`(`username`, `is_system`)
|
||||
VALUES ('Ai', TRUE);
|
||||
|
||||
CREATE TABLE `datacap_chat`
|
||||
(
|
||||
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`active` BOOLEAN DEFAULT TRUE,
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`avatar` VARCHAR(255) DEFAULT NULL,
|
||||
`description` VARCHAR(255) DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_chat_user_relation`
|
||||
(
|
||||
chat_id BIGINT,
|
||||
user_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message`
|
||||
(
|
||||
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`active` BOOLEAN DEFAULT TRUE,
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`content` TEXT DEFAULT NULL,
|
||||
`model` VARCHAR(255) DEFAULT NULL,
|
||||
`type` VARCHAR(100),
|
||||
`prompt_tokens` BIGINT DEFAULT 0,
|
||||
`completion_tokens` BIGINT DEFAULT 0,
|
||||
`total_tokens` BIGINT DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message_user_relation`
|
||||
(
|
||||
message_id BIGINT,
|
||||
user_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message_chat_relation`
|
||||
(
|
||||
message_id BIGINT,
|
||||
chat_id BIGINT
|
||||
);
|
||||
|
@ -794,13 +794,61 @@ WHERE
|
||||
and table_name = ''${table:String}''', 'Get the data column from the database and table', 'Cassandra',
|
||||
'[{"column":"database","type":"String","expression":"${database:String}"},{"column":"table","type":"String","expression":"${table:String}"}]', 1);
|
||||
|
||||
alter table `menus`
|
||||
add column `redirect` bigint default 0,
|
||||
add column `is_new` boolean default false;
|
||||
-- --------------------------------
|
||||
-- Update to 1.12.0 --
|
||||
-- --------------------------------
|
||||
ALTER TABLE `menus`
|
||||
ADD COLUMN `redirect` BIGINT DEFAULT 0,
|
||||
ADD COLUMN `is_new` BOOLEAN DEFAULT FALSE;
|
||||
|
||||
alter table `user_chat`
|
||||
add column `model` varchar(30) default 'gpt-3.5-turbo-0613',
|
||||
add column `prompt_tokens` bigint default 0,
|
||||
add column `completion_tokens` bigint default 0,
|
||||
add column `total_tokens` bigint default 0;
|
||||
RENAME TABLE `users` TO `datacap_user`;
|
||||
|
||||
ALTER TABLE `datacap_user`
|
||||
ADD COLUMN `is_system` BOOLEAN DEFAULT FALSE;
|
||||
|
||||
INSERT INTO `datacap_user`(`username`, `is_system`)
|
||||
VALUES ('Ai', TRUE);
|
||||
|
||||
CREATE TABLE `datacap_chat`
|
||||
(
|
||||
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`active` BOOLEAN DEFAULT TRUE,
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`avatar` VARCHAR(255) DEFAULT NULL,
|
||||
`description` VARCHAR(255) DEFAULT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_chat_user_relation`
|
||||
(
|
||||
chat_id BIGINT,
|
||||
user_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message`
|
||||
(
|
||||
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`active` BOOLEAN DEFAULT TRUE,
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`content` TEXT DEFAULT NULL,
|
||||
`model` VARCHAR(255) DEFAULT NULL,
|
||||
`type` VARCHAR(100),
|
||||
`prompt_tokens` BIGINT DEFAULT 0,
|
||||
`completion_tokens` BIGINT DEFAULT 0,
|
||||
`total_tokens` BIGINT DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message_user_relation`
|
||||
(
|
||||
message_id BIGINT,
|
||||
user_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE `datacap_message_chat_relation`
|
||||
(
|
||||
message_id BIGINT,
|
||||
chat_id BIGINT
|
||||
);
|
||||
|
@ -0,0 +1,21 @@
|
||||
package io.edurt.datacap.service.component.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
@Builder
|
||||
public class UserComponent
|
||||
{
|
||||
@JsonProperty(value = "_id")
|
||||
private Long id;
|
||||
|
||||
@JsonProperty(value = "username")
|
||||
private String username;
|
||||
|
||||
@JsonProperty(value = "avatar")
|
||||
private String avatar;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package io.edurt.datacap.service.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@MappedSuperclass
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"},
|
||||
justification = "I prefer to suppress these FindBugs warnings")
|
||||
public class BaseEntity
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "active")
|
||||
private Boolean active = true;
|
||||
|
||||
@Column(name = "create_time")
|
||||
@CreatedDate
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
@Column(name = "update_time")
|
||||
@LastModifiedDate
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateTime;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package io.edurt.datacap.service.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityListeners;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@EntityListeners(value = AuditingEntityListener.class)
|
||||
@Table(name = "datacap_chat")
|
||||
@SuppressFBWarnings(value = {"EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC"},
|
||||
justification = "I prefer to suppress these FindBugs warnings")
|
||||
public class ChatEntity
|
||||
extends BaseEntity
|
||||
{
|
||||
@Column(name = "avatar")
|
||||
private String avatar;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "datacap_chat_user_relation",
|
||||
joinColumns = @JoinColumn(name = "chat_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
|
||||
@JsonIgnoreProperties(value = {"roles", "thirdConfigure"})
|
||||
private UserEntity user;
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package io.edurt.datacap.service.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.service.enums.MessageType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityListeners;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@EntityListeners(value = AuditingEntityListener.class)
|
||||
@Table(name = "datacap_message")
|
||||
@SuppressFBWarnings(value = {"EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC"},
|
||||
justification = "I prefer to suppress these FindBugs warnings")
|
||||
public class MessageEntity
|
||||
extends BaseEntity
|
||||
{
|
||||
@Column(name = "content")
|
||||
private String content;
|
||||
|
||||
@Column(name = "model")
|
||||
private String model;
|
||||
|
||||
@Column(name = "type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private MessageType type;
|
||||
|
||||
@Column(name = "prompt_tokens")
|
||||
private long promptTokens;
|
||||
|
||||
@Column(name = "completion_tokens")
|
||||
private long completionTokens;
|
||||
|
||||
@Column(name = "total_tokens")
|
||||
private long totalTokens;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "datacap_message_user_relation",
|
||||
joinColumns = @JoinColumn(name = "message_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
|
||||
@JsonIgnoreProperties(value = {"roles", "thirdConfigure"})
|
||||
private UserEntity user;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "datacap_message_chat_relation",
|
||||
joinColumns = @JoinColumn(name = "message_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "chat_id", referencedColumnName = "id"))
|
||||
@JsonIgnoreProperties(value = {"user"})
|
||||
private ChatEntity chat;
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package io.edurt.datacap.service.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.service.validation.ValidationGroup;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@Entity
|
||||
@Builder
|
||||
@Data
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "user_chat")
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP"},
|
||||
justification = "I prefer to suppress these FindBugs warnings")
|
||||
public class UserChatEntity
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotBlank(groups = {
|
||||
ValidationGroup.Crud.Create.class
|
||||
})
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "question")
|
||||
private String question;
|
||||
|
||||
@Column(name = "answer")
|
||||
private String answer;
|
||||
|
||||
@Column(name = "type")
|
||||
private String type;
|
||||
|
||||
@Column(name = "create_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
|
||||
private Timestamp createTime;
|
||||
|
||||
@Column(name = "end_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
|
||||
private Timestamp endTime;
|
||||
|
||||
@Column(name = "elapsed")
|
||||
private Long elapsed;
|
||||
|
||||
@Column(name = "is_new")
|
||||
private boolean isNew;
|
||||
|
||||
@Column(name = "model")
|
||||
private String model;
|
||||
|
||||
@Column(name = "prompt_tokens")
|
||||
private long promptTokens;
|
||||
|
||||
@Column(name = "completion_tokens")
|
||||
private long completionTokens;
|
||||
|
||||
@Column(name = "total_tokens")
|
||||
private long totalTokens;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
@JsonIncludeProperties(value = {"id", "username"})
|
||||
private UserEntity user;
|
||||
|
||||
public void setEndTime(Timestamp endTime)
|
||||
{
|
||||
this.endTime = endTime;
|
||||
this.elapsed = this.endTime.getTime() - this.createTime.getTime();
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.service.validation.ValidationGroup;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
@ -33,11 +34,12 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Builder
|
||||
@Data
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "users",
|
||||
@Table(name = "datacap_user",
|
||||
uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = "username")
|
||||
})
|
||||
@ -68,8 +70,11 @@ public class UserEntity
|
||||
@Column(name = "password")
|
||||
private String password;
|
||||
|
||||
@Column(name = "third_configure")
|
||||
private String thirdConfigure;
|
||||
@Column(name = "chat_configure")
|
||||
private String chatConfigure;
|
||||
|
||||
@Column(name = "is_system")
|
||||
private boolean system;
|
||||
|
||||
@Column(name = "create_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
|
||||
private Timestamp createTime;
|
||||
|
@ -0,0 +1,7 @@
|
||||
package io.edurt.datacap.service.enums;
|
||||
|
||||
public enum MessageType
|
||||
{
|
||||
question,
|
||||
answer
|
||||
}
|
@ -17,4 +17,6 @@ public class AiModel
|
||||
private String host;
|
||||
private String token;
|
||||
private long timeout;
|
||||
// Number of times a context needs to be associated
|
||||
private int contentCount = 5;
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package io.edurt.datacap.service.repository;
|
||||
|
||||
import io.edurt.datacap.service.entity.ChatEntity;
|
||||
import io.edurt.datacap.service.entity.UserEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
public interface ChatRepository
|
||||
extends PagingAndSortingRepository<ChatEntity, Long>
|
||||
{
|
||||
Page<ChatEntity> findAllByUser(UserEntity user, Pageable pageable);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.edurt.datacap.service.repository;
|
||||
|
||||
import io.edurt.datacap.service.entity.ChatEntity;
|
||||
import io.edurt.datacap.service.entity.MessageEntity;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MessageRepository
|
||||
extends PagingAndSortingRepository<MessageEntity, Long>
|
||||
{
|
||||
List<MessageEntity> findAllByChatOrderByCreateTimeAsc(ChatEntity chat);
|
||||
|
||||
@Query(value = "SELECT m " +
|
||||
"FROM MessageEntity AS m " +
|
||||
"WHERE m.chat = ?1 AND m.id < ?2 " +
|
||||
"ORDER BY m.createTime DESC")
|
||||
List<MessageEntity> findTopByChatOrderByCreateTimeDesc(ChatEntity chat, long id, Pageable pageable);
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package io.edurt.datacap.service.repository;
|
||||
|
||||
import io.edurt.datacap.service.entity.UserChatEntity;
|
||||
import io.edurt.datacap.service.entity.UserEntity;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface UserChatRepository
|
||||
extends PagingAndSortingRepository<UserChatEntity, Long>
|
||||
{
|
||||
List<UserChatEntity> findTop5ByUserOrderByIdDesc(UserEntity user);
|
||||
}
|
@ -9,4 +9,6 @@ public interface UserRepository
|
||||
extends PagingAndSortingRepository<UserEntity, Long>
|
||||
{
|
||||
Optional<UserEntity> findByUsername(String username);
|
||||
|
||||
UserEntity findByUsernameAndSystemTrue(String username);
|
||||
}
|
||||
|
@ -25,5 +25,9 @@ public interface BaseService<T>
|
||||
return CommonResponse.success(repository.save(configure));
|
||||
}
|
||||
|
||||
CommonResponse<Long> delete(Long id);
|
||||
default CommonResponse<Long> deleteById(PagingAndSortingRepository repository, Long id)
|
||||
{
|
||||
repository.deleteById(id);
|
||||
return CommonResponse.success(id);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
package io.edurt.datacap.service.service;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.body.FilterBody;
|
||||
import io.edurt.datacap.service.entity.ChatEntity;
|
||||
import io.edurt.datacap.service.entity.PageEntity;
|
||||
|
||||
public interface ChatService
|
||||
extends BaseService<ChatEntity>
|
||||
{
|
||||
CommonResponse<PageEntity<ChatEntity>> getAllByUser(FilterBody filter);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.edurt.datacap.service.service;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.body.UserQuestionBody;
|
||||
import io.edurt.datacap.service.entity.MessageEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MessageService
|
||||
extends BaseService<MessageEntity>
|
||||
{
|
||||
CommonResponse<List<MessageEntity>> getMessageByChatAndUser(Long chatId);
|
||||
|
||||
CommonResponse<MessageEntity> aiReply(UserQuestionBody configure);
|
||||
}
|
@ -5,7 +5,6 @@ import io.edurt.datacap.common.response.JwtResponse;
|
||||
import io.edurt.datacap.service.body.FilterBody;
|
||||
import io.edurt.datacap.service.body.UserNameBody;
|
||||
import io.edurt.datacap.service.body.UserPasswordBody;
|
||||
import io.edurt.datacap.service.body.UserQuestionBody;
|
||||
import io.edurt.datacap.service.entity.PageEntity;
|
||||
import io.edurt.datacap.service.entity.UserEntity;
|
||||
import io.edurt.datacap.service.model.AiModel;
|
||||
@ -27,8 +26,6 @@ public interface UserService
|
||||
|
||||
CommonResponse<Long> changeThirdConfigure(AiModel configure);
|
||||
|
||||
CommonResponse<Object> startChat(UserQuestionBody configure);
|
||||
|
||||
CommonResponse<List<Object>> getSugs(Long id);
|
||||
|
||||
CommonResponse<List<TreeRecord>> getMenus();
|
||||
|
@ -0,0 +1,38 @@
|
||||
package io.edurt.datacap.service.service.impl;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.adapter.PageRequestAdapter;
|
||||
import io.edurt.datacap.service.body.FilterBody;
|
||||
import io.edurt.datacap.service.entity.ChatEntity;
|
||||
import io.edurt.datacap.service.entity.PageEntity;
|
||||
import io.edurt.datacap.service.repository.ChatRepository;
|
||||
import io.edurt.datacap.service.security.UserDetailsService;
|
||||
import io.edurt.datacap.service.service.ChatService;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ChatServiceImpl
|
||||
implements ChatService
|
||||
{
|
||||
private final ChatRepository repository;
|
||||
|
||||
public ChatServiceImpl(ChatRepository repository)
|
||||
{
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<PageEntity<ChatEntity>> getAll(PagingAndSortingRepository repository, FilterBody filter)
|
||||
{
|
||||
return CommonResponse.success(PageEntity.build(repository.findAll(PageRequestAdapter.of(filter))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<PageEntity<ChatEntity>> getAllByUser(FilterBody filter)
|
||||
{
|
||||
Pageable pageable = PageRequestAdapter.of(filter);
|
||||
return CommonResponse.success(PageEntity.build(repository.findAllByUser(UserDetailsService.getUser(), pageable)));
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package io.edurt.datacap.service.service.impl;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.repository.admin.MenuRepository;
|
||||
import io.edurt.datacap.service.service.MenuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -15,10 +14,4 @@ public class MenuServiceImpl
|
||||
{
|
||||
this.menuRepository = menuRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Long> delete(Long id)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,250 @@
|
||||
package io.edurt.datacap.service.service.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.common.enums.ServiceState;
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.common.utils.AiSupportUtils;
|
||||
import io.edurt.datacap.common.utils.JsonUtils;
|
||||
import io.edurt.datacap.service.body.UserQuestionBody;
|
||||
import io.edurt.datacap.service.entity.ChatEntity;
|
||||
import io.edurt.datacap.service.entity.MessageEntity;
|
||||
import io.edurt.datacap.service.entity.UserEntity;
|
||||
import io.edurt.datacap.service.enums.MessageType;
|
||||
import io.edurt.datacap.service.model.AiModel;
|
||||
import io.edurt.datacap.service.repository.MessageRepository;
|
||||
import io.edurt.datacap.service.repository.UserRepository;
|
||||
import io.edurt.datacap.service.security.UserDetailsService;
|
||||
import io.edurt.datacap.service.service.MessageService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.apache.commons.lang.text.StrSubstitutor;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.devlive.sdk.openai.OpenAiClient;
|
||||
import org.devlive.sdk.openai.entity.CompletionChatEntity;
|
||||
import org.devlive.sdk.openai.entity.CompletionMessageEntity;
|
||||
import org.devlive.sdk.openai.entity.UsageEntity;
|
||||
import org.devlive.sdk.openai.model.CompletionMessageModel;
|
||||
import org.devlive.sdk.openai.response.CompleteChatResponse;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@SuppressFBWarnings(value = {"RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE"},
|
||||
justification = "I prefer to suppress these FindBugs warnings")
|
||||
public class MessageServiceImpl
|
||||
implements MessageService
|
||||
{
|
||||
private final MessageRepository repository;
|
||||
private final UserRepository userRepository;
|
||||
private final Environment environment;
|
||||
|
||||
public MessageServiceImpl(MessageRepository repository, UserRepository userRepository, Environment environment)
|
||||
{
|
||||
this.repository = repository;
|
||||
this.userRepository = userRepository;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<MessageEntity> saveOrUpdate(PagingAndSortingRepository repository, MessageEntity configure)
|
||||
{
|
||||
Optional<UserEntity> userOptional = this.userRepository.findById(configure.getUser().getId());
|
||||
if (!userOptional.isPresent()) {
|
||||
return CommonResponse.failure(ServiceState.USER_NOT_FOUND);
|
||||
}
|
||||
String openApiHost = environment.getProperty("datacap.openai.backend");
|
||||
String openApiToken = environment.getProperty("datacap.openai.token");
|
||||
String openApiModel = environment.getProperty("datacap.openai.model");
|
||||
long openApiTimeout = Long.parseLong(environment.getProperty("datacap.openai.timeout"));
|
||||
|
||||
UserEntity user = userOptional.get();
|
||||
MessageEntity questionMessage = MessageEntity.builder()
|
||||
.user(user)
|
||||
.chat(configure.getChat())
|
||||
.model(StringUtils.isNotEmpty(configure.getModel()) ? configure.getModel() : openApiModel)
|
||||
.content(configure.getContent())
|
||||
.name(UUID.randomUUID().toString())
|
||||
.type(MessageType.question)
|
||||
.build();
|
||||
this.repository.save(questionMessage);
|
||||
int contentCount = 5;
|
||||
boolean getContent = true;
|
||||
if (StringUtils.isNotEmpty(configure.getModel())) {
|
||||
openApiModel = configure.getModel();
|
||||
}
|
||||
// If user-defined configuration, use user configuration information
|
||||
if (StringUtils.isNotEmpty(user.getChatConfigure())) {
|
||||
AiModel aiModel = JsonUtils.toObject(user.getChatConfigure(), AiModel.class);
|
||||
if (StringUtils.isNotEmpty(aiModel.getToken())) {
|
||||
openApiHost = aiModel.getHost();
|
||||
openApiToken = aiModel.getToken();
|
||||
}
|
||||
if (aiModel.getTimeout() > 0) {
|
||||
openApiTimeout = aiModel.getTimeout();
|
||||
}
|
||||
if (aiModel.getContentCount() > 0) {
|
||||
contentCount = aiModel.getContentCount();
|
||||
}
|
||||
}
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.writeTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.readTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.build();
|
||||
try (OpenAiClient openAiClient = OpenAiClient.builder()
|
||||
.apiHost(openApiHost)
|
||||
.apiKey(openApiToken)
|
||||
.client(okHttpClient)
|
||||
.build()) {
|
||||
List<CompletionMessageEntity> messages = new ArrayList<>();
|
||||
// Get the context in the conversation * 2
|
||||
if (getContent) {
|
||||
this.repository.findTopByChatOrderByCreateTimeDesc(configure.getChat(), questionMessage.getId(), Pageable.ofSize(contentCount * 2))
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(MessageEntity::getId))
|
||||
.forEach(message -> {
|
||||
String role = message.getType() == MessageType.question ? CompletionMessageModel.USER.getName() : CompletionMessageModel.ASSISTANT.getName();
|
||||
CompletionMessageEntity completionMessage = CompletionMessageEntity.builder()
|
||||
.role(role)
|
||||
.content(message.getContent())
|
||||
.build();
|
||||
messages.add(completionMessage);
|
||||
});
|
||||
}
|
||||
CompletionMessageEntity message = CompletionMessageEntity.builder()
|
||||
.role(CompletionMessageModel.USER.getName())
|
||||
.content(questionMessage.getContent())
|
||||
.build();
|
||||
messages.add(message);
|
||||
CompletionChatEntity chatCompletion = CompletionChatEntity.builder()
|
||||
.messages(messages)
|
||||
.maxTokens(2048)
|
||||
.model(openApiModel)
|
||||
.build();
|
||||
CompleteChatResponse chatCompletionResponse = openAiClient.createChatCompletion(chatCompletion);
|
||||
List<String> answer = Lists.newArrayList();
|
||||
chatCompletionResponse.getChoices()
|
||||
.forEach(e -> answer.add(e.getMessage().getContent()));
|
||||
UsageEntity usage = chatCompletionResponse.getUsage();
|
||||
UserEntity aiUser = this.userRepository.findByUsernameAndSystemTrue("Ai");
|
||||
MessageEntity answerEntity = MessageEntity.builder()
|
||||
.user(aiUser)
|
||||
.chat(configure.getChat())
|
||||
.model(openApiModel)
|
||||
.content(String.join("\n", answer))
|
||||
.type(MessageType.answer)
|
||||
.promptTokens(usage.getPromptTokens())
|
||||
.completionTokens(usage.getCompletionTokens())
|
||||
.totalTokens(usage.getTotalTokens())
|
||||
.name(UUID.randomUUID().toString())
|
||||
.build();
|
||||
this.repository.save(answerEntity);
|
||||
return CommonResponse.success(answerEntity);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return CommonResponse.failure(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<List<MessageEntity>> getMessageByChatAndUser(Long chatId)
|
||||
{
|
||||
ChatEntity chat = ChatEntity.builder()
|
||||
.id(chatId)
|
||||
.build();
|
||||
return CommonResponse.success(this.repository.findAllByChatOrderByCreateTimeAsc(chat));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<MessageEntity> aiReply(UserQuestionBody configure)
|
||||
{
|
||||
String openApiHost = environment.getProperty("datacap.openai.backend");
|
||||
String openApiToken = environment.getProperty("datacap.openai.token");
|
||||
String openApiModel = environment.getProperty("datacap.openai.model");
|
||||
long openApiTimeout = Long.parseLong(environment.getProperty("datacap.openai.timeout"));
|
||||
UserEntity user = this.userRepository.findById(UserDetailsService.getUser().getId()).get();
|
||||
if (StringUtils.isNotEmpty(configure.getModel())) {
|
||||
openApiModel = configure.getModel();
|
||||
}
|
||||
// If user-defined configuration, use user configuration information
|
||||
String forwardContent = null;
|
||||
if (StringUtils.isNotEmpty(user.getChatConfigure())) {
|
||||
AiModel aiModel = JsonUtils.toObject(user.getChatConfigure(), AiModel.class);
|
||||
if (StringUtils.isNotEmpty(aiModel.getToken())) {
|
||||
openApiHost = aiModel.getHost();
|
||||
openApiToken = aiModel.getToken();
|
||||
}
|
||||
if (aiModel.getTimeout() > 0) {
|
||||
openApiTimeout = aiModel.getTimeout();
|
||||
}
|
||||
}
|
||||
try {
|
||||
AiSupportUtils.AiSupportEnum type = AiSupportUtils.AiSupportEnum.valueOf(configure.getTransType());
|
||||
String replaceContent = AiSupportUtils.getValue(configure.getLocale(), type);
|
||||
Properties properties = new Properties();
|
||||
properties.put("sql", configure.getContent());
|
||||
if (ObjectUtils.isNotEmpty(configure.getEngine())) {
|
||||
properties.put("engine", configure.getEngine());
|
||||
}
|
||||
if (ObjectUtils.isNotEmpty(configure.getError())) {
|
||||
properties.put("error", configure.getError());
|
||||
}
|
||||
StrSubstitutor sub = new StrSubstitutor(properties);
|
||||
forwardContent = sub.replace(replaceContent);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
log.warn("Ai type not set, ignore .");
|
||||
}
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.writeTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.readTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.build();
|
||||
try (OpenAiClient openAiClient = OpenAiClient.builder()
|
||||
.apiHost(openApiHost)
|
||||
.apiKey(openApiToken)
|
||||
.client(okHttpClient)
|
||||
.build()) {
|
||||
List<CompletionMessageEntity> messages = Lists.newArrayList(CompletionMessageEntity.builder()
|
||||
.role(CompletionMessageModel.USER.getName())
|
||||
.content(forwardContent)
|
||||
.build());
|
||||
CompletionChatEntity chatCompletion = CompletionChatEntity.builder()
|
||||
.messages(messages)
|
||||
.maxTokens(2048)
|
||||
.model(openApiModel)
|
||||
.build();
|
||||
CompleteChatResponse chatCompletionResponse = openAiClient.createChatCompletion(chatCompletion);
|
||||
List<String> answer = Lists.newArrayList();
|
||||
chatCompletionResponse.getChoices()
|
||||
.forEach(e -> answer.add(e.getMessage().getContent()));
|
||||
UsageEntity usage = chatCompletionResponse.getUsage();
|
||||
MessageEntity answerEntity = MessageEntity.builder()
|
||||
.model(openApiModel)
|
||||
.content(String.join("\n", answer))
|
||||
.type(MessageType.answer)
|
||||
.promptTokens(usage.getPromptTokens())
|
||||
.completionTokens(usage.getCompletionTokens())
|
||||
.totalTokens(usage.getTotalTokens())
|
||||
.name(UUID.randomUUID().toString())
|
||||
.build();
|
||||
return CommonResponse.success(answerEntity);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return CommonResponse.failure(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -225,10 +225,4 @@ public class PipelineServiceImpl
|
||||
}
|
||||
properties.put(field.getField(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Long> delete(Long id)
|
||||
{
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
|
@ -34,12 +34,6 @@ public class RoleServiceImpl
|
||||
this.menuRepository = menuRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Long> delete(Long id)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Object> getMenusByRoleId(Long roleId)
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
package io.edurt.datacap.service.service.impl;
|
||||
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.service.service.ScheduledTaskService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -8,9 +7,4 @@ import org.springframework.stereotype.Service;
|
||||
public class ScheduledTaskServiceImpl
|
||||
implements ScheduledTaskService
|
||||
{
|
||||
@Override
|
||||
public CommonResponse<Long> delete(Long id)
|
||||
{
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -5,40 +5,27 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.common.enums.ServiceState;
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.common.response.JwtResponse;
|
||||
import io.edurt.datacap.common.utils.AiSupportUtils;
|
||||
import io.edurt.datacap.common.utils.JsonUtils;
|
||||
import io.edurt.datacap.service.adapter.PageRequestAdapter;
|
||||
import io.edurt.datacap.service.audit.AuditUserLog;
|
||||
import io.edurt.datacap.service.body.FilterBody;
|
||||
import io.edurt.datacap.service.body.UserNameBody;
|
||||
import io.edurt.datacap.service.body.UserPasswordBody;
|
||||
import io.edurt.datacap.service.body.UserQuestionBody;
|
||||
import io.edurt.datacap.service.entity.MenuEntity;
|
||||
import io.edurt.datacap.service.entity.PageEntity;
|
||||
import io.edurt.datacap.service.entity.RoleEntity;
|
||||
import io.edurt.datacap.service.entity.SourceEntity;
|
||||
import io.edurt.datacap.service.entity.UserChatEntity;
|
||||
import io.edurt.datacap.service.entity.UserEntity;
|
||||
import io.edurt.datacap.service.model.AiModel;
|
||||
import io.edurt.datacap.service.record.TreeRecord;
|
||||
import io.edurt.datacap.service.repository.RoleRepository;
|
||||
import io.edurt.datacap.service.repository.SourceRepository;
|
||||
import io.edurt.datacap.service.repository.UserChatRepository;
|
||||
import io.edurt.datacap.service.repository.UserRepository;
|
||||
import io.edurt.datacap.service.security.UserDetailsService;
|
||||
import io.edurt.datacap.service.service.JwtService;
|
||||
import io.edurt.datacap.service.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.apache.commons.lang.text.StrSubstitutor;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.devlive.sdk.openai.OpenAiClient;
|
||||
import org.devlive.sdk.openai.entity.CompletionChatEntity;
|
||||
import org.devlive.sdk.openai.entity.CompletionMessageEntity;
|
||||
import org.devlive.sdk.openai.entity.UsageEntity;
|
||||
import org.devlive.sdk.openai.model.CompletionMessageModel;
|
||||
import org.devlive.sdk.openai.response.CompleteChatResponse;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
@ -49,19 +36,14 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@ -73,7 +55,6 @@ public class UserServiceImpl
|
||||
{
|
||||
private final UserRepository userRepository;
|
||||
private final RoleRepository roleRepository;
|
||||
private final UserChatRepository userChatRepository;
|
||||
private final SourceRepository sourceRepository;
|
||||
private final PasswordEncoder encoder;
|
||||
private final AuthenticationManager authenticationManager;
|
||||
@ -81,11 +62,10 @@ public class UserServiceImpl
|
||||
private final RedisTemplate redisTemplate;
|
||||
private final Environment environment;
|
||||
|
||||
public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository, UserChatRepository userChatRepository, SourceRepository sourceRepository, PasswordEncoder encoder, AuthenticationManager authenticationManager, JwtService jwtService, RedisTemplate redisTemplate, Environment environment)
|
||||
public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository, SourceRepository sourceRepository, PasswordEncoder encoder, AuthenticationManager authenticationManager, JwtService jwtService, RedisTemplate redisTemplate, Environment environment)
|
||||
{
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.userChatRepository = userChatRepository;
|
||||
this.sourceRepository = sourceRepository;
|
||||
this.encoder = encoder;
|
||||
this.authenticationManager = authenticationManager;
|
||||
@ -195,133 +175,11 @@ public class UserServiceImpl
|
||||
return CommonResponse.failure(ServiceState.USER_NOT_FOUND);
|
||||
}
|
||||
UserEntity user = userOptional.get();
|
||||
user.setThirdConfigure(JsonUtils.toJSON(configure));
|
||||
user.setChatConfigure(JsonUtils.toJSON(configure));
|
||||
this.userRepository.save(user);
|
||||
return CommonResponse.success(user.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Object> startChat(UserQuestionBody configure)
|
||||
{
|
||||
Optional<UserEntity> userOptional = this.userRepository.findById(UserDetailsService.getUser().getId());
|
||||
if (!userOptional.isPresent()) {
|
||||
return CommonResponse.failure(ServiceState.USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!configure.getType().equals("ChatGPT")) {
|
||||
return CommonResponse.failure("Not supported");
|
||||
}
|
||||
UserEntity user = userOptional.get();
|
||||
UserChatEntity userChat = UserChatEntity.builder()
|
||||
.question(configure.getContent())
|
||||
.user(user)
|
||||
.name(UUID.randomUUID().toString())
|
||||
.type(configure.getType())
|
||||
.createTime(Timestamp.valueOf(LocalDateTime.now()))
|
||||
.isNew(configure.isNewChat())
|
||||
.build();
|
||||
String openApiHost = environment.getProperty("datacap.openai.backend");
|
||||
String openApiToken = environment.getProperty("datacap.openai.token");
|
||||
String openApiModel = environment.getProperty("datacap.openai.model");
|
||||
long openApiTimeout = Long.parseLong(environment.getProperty("datacap.openai.timeout"));
|
||||
if (StringUtils.isNotEmpty(configure.getModel())) {
|
||||
openApiModel = configure.getModel();
|
||||
}
|
||||
// If user-defined configuration, use user configuration information
|
||||
if (StringUtils.isNotEmpty(user.getThirdConfigure())) {
|
||||
AiModel aiModel = JsonUtils.toObject(user.getThirdConfigure(), AiModel.class);
|
||||
if (StringUtils.isNotEmpty(aiModel.getToken())) {
|
||||
openApiHost = aiModel.getHost();
|
||||
openApiToken = aiModel.getToken();
|
||||
}
|
||||
if (aiModel.getTimeout() > 0) {
|
||||
openApiTimeout = aiModel.getTimeout();
|
||||
}
|
||||
}
|
||||
// Build the Open AI client
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.writeTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.readTimeout(openApiTimeout, TimeUnit.SECONDS)
|
||||
.build();
|
||||
OpenAiClient openAiClient = OpenAiClient.builder()
|
||||
.apiHost(openApiHost)
|
||||
.apiKey(openApiToken)
|
||||
.client(okHttpClient)
|
||||
.build();
|
||||
|
||||
List<String> content = new ArrayList<>();
|
||||
String forwardContent = configure.getContent();
|
||||
try {
|
||||
AiSupportUtils.AiSupportEnum type = AiSupportUtils.AiSupportEnum.valueOf(configure.getTransType());
|
||||
String replaceContent = AiSupportUtils.getValue(configure.getLocale(), type);
|
||||
Properties properties = new Properties();
|
||||
properties.put("sql", configure.getContent());
|
||||
if (ObjectUtils.isNotEmpty(configure.getEngine())) {
|
||||
properties.put("engine", configure.getEngine());
|
||||
}
|
||||
if (ObjectUtils.isNotEmpty(configure.getError())) {
|
||||
properties.put("error", configure.getError());
|
||||
}
|
||||
StrSubstitutor sub = new StrSubstitutor(properties);
|
||||
forwardContent = sub.replace(replaceContent);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
log.warn("Ai type not set, ignore .");
|
||||
}
|
||||
try {
|
||||
List<CompletionMessageEntity> messages = new ArrayList<>();
|
||||
// Extract database history for recording context if source is dialog mode
|
||||
boolean saved = false;
|
||||
if (StringUtils.isNotEmpty(configure.getFrom()) && configure.getFrom().equalsIgnoreCase("chat")) {
|
||||
if (!configure.isNewChat()) {
|
||||
this.userChatRepository.findTop5ByUserOrderByIdDesc(UserDetailsService.getUser())
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(UserChatEntity::getId))
|
||||
.forEach(userChatHistory -> {
|
||||
CompletionMessageEntity question = CompletionMessageEntity.builder()
|
||||
.role(CompletionMessageModel.USER.getName())
|
||||
.content(userChatHistory.getQuestion())
|
||||
.build();
|
||||
messages.add(question);
|
||||
CompletionMessageEntity answer = CompletionMessageEntity.builder()
|
||||
.role(CompletionMessageModel.ASSISTANT.getName())
|
||||
.content(userChatHistory.getAnswer())
|
||||
.build();
|
||||
messages.add(answer);
|
||||
});
|
||||
}
|
||||
saved = true;
|
||||
}
|
||||
CompletionMessageEntity message = CompletionMessageEntity.builder()
|
||||
.role(CompletionMessageModel.USER.getName())
|
||||
.content(forwardContent)
|
||||
.build();
|
||||
messages.add(message);
|
||||
CompletionChatEntity chatCompletion = CompletionChatEntity.builder()
|
||||
.messages(messages)
|
||||
.model(openApiModel)
|
||||
.build();
|
||||
CompleteChatResponse chatCompletionResponse = openAiClient.createChatCompletion(chatCompletion);
|
||||
chatCompletionResponse.getChoices()
|
||||
.forEach(e -> content.add(e.getMessage().getContent()));
|
||||
userChat.setEndTime(Timestamp.valueOf(LocalDateTime.now()));
|
||||
userChat.setAnswer(String.join("\n", content));
|
||||
userChat.setModel(chatCompletionResponse.getModel());
|
||||
UsageEntity usage = chatCompletionResponse.getUsage();
|
||||
userChat.setPromptTokens(usage.getPromptTokens());
|
||||
userChat.setCompletionTokens(usage.getCompletionTokens());
|
||||
userChat.setTotalTokens(usage.getTotalTokens());
|
||||
if (saved) {
|
||||
this.userChatRepository.save(userChat);
|
||||
}
|
||||
return CommonResponse.success(userChat);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return CommonResponse.failure(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<List<Object>> getSugs(Long id)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.0-5",
|
||||
"@kangc/v-md-editor": "^2.3.15",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/watermark-dom": "^2.3.1",
|
||||
"ag-grid-community": "^29.3.5",
|
||||
@ -21,11 +22,13 @@
|
||||
"core-js": "^3.8.3",
|
||||
"echarts": "^5.4.0",
|
||||
"export-to-csv": "^0.2.1",
|
||||
"highlight.js": "^11.8.0",
|
||||
"install": "^0.13.0",
|
||||
"lodash": "^4.17.21",
|
||||
"monaco-editor-vue3": "^0.1.6",
|
||||
"monaco-editor-webpack-plugin": "^7.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"squel": "^5.13.0",
|
||||
"view-ui-plus": "^1.3.1",
|
||||
"vue": "^3.2.13",
|
||||
|
42
core/datacap-web/src/components/loading/CircularLoading.vue
Normal file
42
core/datacap-web/src/components/loading/CircularLoading.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<Spin fix
|
||||
:show="show">
|
||||
<Icon type="ios-loading"
|
||||
size=18
|
||||
class="spin-icon-load">
|
||||
</Icon>
|
||||
<div>Loading</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {defineComponent} from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "CircularLoading",
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.spin-icon-load {
|
||||
animation: ani-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes ani-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
54
core/datacap-web/src/components/markdown/MarkdownView.vue
Normal file
54
core/datacap-web/src/components/markdown/MarkdownView.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<VMdPreview v-if="content"
|
||||
:text="content">
|
||||
</VMdPreview>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {defineComponent} from "vue";
|
||||
import VMdPreview from '@kangc/v-md-editor/lib/preview'
|
||||
import '@kangc/v-md-editor/lib/style/preview.css';
|
||||
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js';
|
||||
import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
|
||||
|
||||
import Prism from 'prismjs';
|
||||
import 'prismjs/components/prism-json';
|
||||
import 'prismjs/components/prism-java';
|
||||
import 'prismjs/components/prism-c';
|
||||
import 'prismjs/components/prism-css'
|
||||
import 'prismjs/components/prism-typescript'
|
||||
import 'prismjs/components/prism-javascript'
|
||||
import 'prismjs/components/prism-http'
|
||||
import 'prismjs/components/prism-powershell'
|
||||
import 'prismjs/components/prism-antlr4'
|
||||
import 'prismjs/components/prism-scala'
|
||||
import 'prismjs/components/prism-sass'
|
||||
import 'prismjs/components/prism-sql'
|
||||
import 'prismjs/components/prism-json5'
|
||||
import createLineNumberPlugin from '@kangc/v-md-editor/lib/plugins/line-number/index';
|
||||
import createCopyCodePlugin from '@kangc/v-md-editor/lib/plugins/copy-code/index';
|
||||
import '@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css';
|
||||
|
||||
VMdPreview.use(vuepressTheme, {
|
||||
Prism
|
||||
});
|
||||
|
||||
VMdPreview.use(createLineNumberPlugin())
|
||||
VMdPreview.use(createCopyCodePlugin())
|
||||
|
||||
export default defineComponent({
|
||||
name: "MarkdownView",
|
||||
props: {
|
||||
content: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
}
|
||||
},
|
||||
components: {VMdPreview}
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
</style>
|
@ -26,7 +26,7 @@ class Entity<T extends EntityProperties = EntityProperties>
|
||||
public static default(): Entity<Pick<EntityProperties, 'id' | 'name' | 'description'>>
|
||||
{
|
||||
return new Entity({
|
||||
id: 1,
|
||||
id: 0,
|
||||
name: 'admin',
|
||||
description: 'Administrator',
|
||||
});
|
||||
@ -35,10 +35,15 @@ class Entity<T extends EntityProperties = EntityProperties>
|
||||
/**
|
||||
* Get the value of the specified property.
|
||||
*/
|
||||
public get<K extends keyof T>(prop: K): T[K]
|
||||
public field<K extends keyof T>(prop: K): T[K]
|
||||
{
|
||||
return this.props[prop];
|
||||
}
|
||||
|
||||
public get(): T
|
||||
{
|
||||
return this.props;
|
||||
}
|
||||
}
|
||||
|
||||
class EntityBuilder<P extends EntityProperties = EntityProperties>
|
||||
|
@ -123,4 +123,5 @@ export default {
|
||||
chat: 'Chat',
|
||||
timeout: 'Timeout',
|
||||
seconds: 'Seconds',
|
||||
avatar: 'Avatar',
|
||||
}
|
||||
|
@ -8,5 +8,7 @@ export default {
|
||||
accountSetting: 'Account Setting',
|
||||
changeUsername: 'Change the username',
|
||||
newUsername: 'New username',
|
||||
log: 'Login Log'
|
||||
log: 'Login Log',
|
||||
changeChatGpt: 'Change the chatgpt',
|
||||
contentCount: 'Content Count',
|
||||
}
|
||||
|
@ -122,5 +122,6 @@ export default {
|
||||
new: '新',
|
||||
chat: '对话',
|
||||
timeout: '超时时间',
|
||||
seconds: '秒'
|
||||
seconds: '秒',
|
||||
avatar: '头像'
|
||||
}
|
||||
|
@ -8,5 +8,7 @@ export default {
|
||||
accountSetting: '账号设置',
|
||||
changeUsername: '修改用户名',
|
||||
newUsername: '新用户名',
|
||||
log: '登录日志'
|
||||
log: '登录日志',
|
||||
changeChatGpt: '修改 ChatGPT',
|
||||
contentCount: '上下文关联数'
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ export interface User
|
||||
username: string;
|
||||
thirdConfigure: ThirdConfigure;
|
||||
createTime?: string;
|
||||
id?: number;
|
||||
}
|
||||
|
||||
export class UserQuestion
|
||||
@ -38,5 +39,6 @@ export class ThirdConfigure
|
||||
token = '';
|
||||
host = '';
|
||||
model = '';
|
||||
timeout: number = null;
|
||||
timeout = 30;
|
||||
contentCount = 5
|
||||
}
|
||||
|
@ -52,11 +52,14 @@ export abstract class BaseService<T>
|
||||
}
|
||||
}
|
||||
|
||||
deleteById(id: number): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpCommon().delete(`${this.baseUrl}/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the corresponding data according to the name
|
||||
* @param name
|
||||
*/
|
||||
abstract getByName<T>(name: string): Promise<ResponseModel>;
|
||||
|
||||
abstract deleteById(id: number): Promise<ResponseModel>;
|
||||
}
|
||||
|
26
core/datacap-web/src/services/ChatService.ts
Normal file
26
core/datacap-web/src/services/ChatService.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import {BaseService} from "@/services/BaseService";
|
||||
import {ResponseModel} from "@/model/ResponseModel";
|
||||
import {HttpCommon} from "@/common/HttpCommon";
|
||||
|
||||
const baseUrl = '/api/v1/chat';
|
||||
|
||||
export class ChatService
|
||||
extends BaseService<any>
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(baseUrl);
|
||||
}
|
||||
|
||||
getMessages(id: number): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpCommon().get(`${baseUrl}/${id}/messages`);
|
||||
}
|
||||
|
||||
getByName<T>(name: string): Promise<ResponseModel>
|
||||
{
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
export default new ChatService();
|
27
core/datacap-web/src/services/MessageService.ts
Normal file
27
core/datacap-web/src/services/MessageService.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import {BaseService} from "@/services/BaseService";
|
||||
import {ResponseModel} from "@/model/ResponseModel";
|
||||
import {UserQuestion} from "@/model/User";
|
||||
import {HttpCommon} from "@/common/HttpCommon";
|
||||
|
||||
const baseUrl = '/api/v1/message';
|
||||
|
||||
export class MessageService
|
||||
extends BaseService<any>
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(baseUrl);
|
||||
}
|
||||
|
||||
getByName<T>(name: string): Promise<ResponseModel>
|
||||
{
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
aiReply(configure: UserQuestion): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpCommon().post(baseUrl + '/ai/reply', configure);
|
||||
}
|
||||
}
|
||||
|
||||
export default new MessageService();
|
@ -3,7 +3,6 @@ import {ResponseModel} from "@/model/ResponseModel";
|
||||
import {UserPassword} from "@/model/UserPassword";
|
||||
import {UserName} from "@/model/UserName";
|
||||
import {Filter} from "@/model/Filter";
|
||||
import {UserQuestion} from "@/model/User";
|
||||
|
||||
const baseUrl = "/api/v1/user";
|
||||
|
||||
@ -29,11 +28,6 @@ class UserService
|
||||
return new HttpCommon().put(baseUrl + '/changeThirdConfigure', configure);
|
||||
}
|
||||
|
||||
startChat(configure: UserQuestion): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpCommon().post(baseUrl + '/startChat', configure);
|
||||
}
|
||||
|
||||
getLogs(filter: Filter): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpCommon().post(baseUrl + '/log', filter);
|
||||
|
@ -1,126 +1,171 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card dis-hover
|
||||
style="width:100%; minHeight: 150px;">
|
||||
<template #title>
|
||||
{{ $t('common.chatgpt') }}
|
||||
<Select v-model="gptModel"
|
||||
style="width:200px">
|
||||
<Option v-for="model in models"
|
||||
:value="model"
|
||||
v-bind:key="model">
|
||||
{{ model }}
|
||||
</Option>
|
||||
</Select>
|
||||
</template>
|
||||
<template #extra>
|
||||
<Tooltip :content="$t('common.settings')" transfer>
|
||||
<Button type="primary" size="small" shape="circle" icon="ios-cog" @click="handlerVisibleDetail(true)"></Button>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<div>
|
||||
<Layout style="background-color: #FFFFFF;">
|
||||
<Content style="padding: 0px 0px 0px 10px;">
|
||||
<div ref="scrollDiv" style="height: 300px; max-height: 300px; overflow: auto;">
|
||||
<div v-for="item in userQuestionItems"
|
||||
:key="item">
|
||||
<Divider :orientation="item.isSelf ? 'left' : 'right'">
|
||||
<Avatar v-if="item.isSelf" icon="ios-person"></Avatar>
|
||||
<Avatar v-else icon="md-ionitron" style="background-color: #87d068;"></Avatar>
|
||||
</Divider>
|
||||
<div :style="{margin: '0px 10px', float: item.isSelf ? '' : 'right'}">
|
||||
<Card dis-hover
|
||||
:bordered="false">
|
||||
<VMarkdownView v-if="item.content"
|
||||
:mode="'light'"
|
||||
:content="item.content.answer">
|
||||
</VMarkdownView>
|
||||
<div v-if="!item.isSelf"
|
||||
style="margin-top: 5px; float: right;">
|
||||
Model:
|
||||
<Text strong>{{ item.content.model }}</Text>
|
||||
<Divider type="vertical"/>
|
||||
Prompt Tokens:
|
||||
<CountUp :end="item.content.promptTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
<Divider type="vertical"/>
|
||||
Completion Tokens:
|
||||
<CountUp :end="item.content.completionTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
<Divider type="vertical"/>
|
||||
Total Tokens:
|
||||
<CountUp :end="item.content.totalTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<Layout>
|
||||
<Sider style="background-color: #FFFFFF">
|
||||
<Card dis-hover
|
||||
padding="0">
|
||||
<template #title>
|
||||
{{ $t('common.chat') }}
|
||||
</template>
|
||||
<template #extra>
|
||||
<Tooltip :content="$t('common.create') + $t('common.chat')">
|
||||
<Button type="primary"
|
||||
shape="circle"
|
||||
size="small"
|
||||
style="margin-top: -10px;"
|
||||
icon="md-add"
|
||||
@click="handlerCreateChat(true)">
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<RadioGroup v-model="selectedChat"
|
||||
vertical
|
||||
style="margin: 3px 3px 3px 3px; height: 500px; width: 100%; overflow: auto;"
|
||||
@on-change="handlerChangeChat">
|
||||
<Radio v-for="item in chats"
|
||||
:key="item.id"
|
||||
:label="item"
|
||||
border
|
||||
style="margin-top: 3px; padding: 3px 5px; height: 40px;">
|
||||
<Avatar v-if="item.avatar"
|
||||
:src="item.avatar">
|
||||
</Avatar>
|
||||
<Avatar v-else>
|
||||
{{ item.name }}
|
||||
</Avatar>
|
||||
{{ item.name }}
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
<CircularLoading v-if="loadingChats"
|
||||
:show="loadingChats">
|
||||
</CircularLoading>
|
||||
</Card>
|
||||
</Sider>
|
||||
<Content style="margin-left: 3px;">
|
||||
<Card v-if="selectedChat"
|
||||
dis-hover
|
||||
style="width:100%; minHeight: 150px;">
|
||||
<template #title>
|
||||
<Text strong>{{ $t('common.chat') }}</Text>
|
||||
: {{ selectedChat.name }}
|
||||
</template>
|
||||
<template #extra>
|
||||
<div style="margin-top: -13px;">
|
||||
Prompt Tokens:
|
||||
<CountUp :end="promptTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
<Divider type="vertical"/>
|
||||
Completion Tokens:
|
||||
<CountUp :end="completionTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
<Divider type="vertical"/>
|
||||
Total Tokens:
|
||||
<CountUp :end="totalTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
</div>
|
||||
</Content>
|
||||
<Divider></Divider>
|
||||
<Footer style="background-color: #FFFFFF;">
|
||||
<Row>
|
||||
<Col span="20">
|
||||
<Input v-model="userQuestionContext"
|
||||
type="textarea"
|
||||
:autosize="{minRows: 2,maxRows: 5}">
|
||||
</Input>
|
||||
</Col>
|
||||
<Col span="2" offset="1">
|
||||
<Button type="primary"
|
||||
icon="md-send"
|
||||
:disabled="!userQuestionContext"
|
||||
:loading="startChatLoading"
|
||||
@click="handlerStartChat()">
|
||||
{{ $t('common.send') }}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Footer>
|
||||
</Layout>
|
||||
</div>
|
||||
<Spin size="large" fix :show="loading"></Spin>
|
||||
</Card>
|
||||
|
||||
<Modal v-if="visibleModel" v-model="visibleModel" :title="$t('common.chatgpt') +' ' + $t('common.settings')"
|
||||
:mask-closable="false" :closable="false">
|
||||
<Form :label-width="80">
|
||||
<FormItem :label="$t('common.token')">
|
||||
<Input v-model="userInfo.thirdConfigure.token" type="text" placeholder="example: sk-xxxx"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$t('common.proxy')">
|
||||
<Input v-model="userInfo.thirdConfigure.host" type="text"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$t('common.timeout')">
|
||||
<InputNumber v-model="userInfo.thirdConfigure.timeout"/>
|
||||
<Text strong
|
||||
style="margin-left: 5px;">
|
||||
{{ $t('common.seconds') }}
|
||||
</Text>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<Space>
|
||||
<Button type="error" @click="handlerVisibleDetail(false)">{{ $t('common.cancel') }}</Button>
|
||||
<Button type="primary" icon="md-document" @click="handlerSave()">{{ $t('common.save') }}</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
<Layout style="background-color: #FFFFFF;">
|
||||
<Content style="padding: 0px 0px 0px 10px;">
|
||||
<div ref="scrollDiv" style="height: 300px; max-height: 300px; overflow: auto;">
|
||||
<div v-for="item in messages"
|
||||
:key="item">
|
||||
<Divider :orientation="item.type === 'question' ? 'left' : 'right'">
|
||||
<Avatar v-if="item.type === 'question'">
|
||||
{{ userInfo.username }}
|
||||
</Avatar>
|
||||
<Avatar v-else
|
||||
icon="md-ionitron"
|
||||
style="background-color: #87d068;">
|
||||
</Avatar>
|
||||
</Divider>
|
||||
<div :style="{margin: '0px 10px', float: item.type === 'question' ? '' : 'right'}">
|
||||
<Card dis-hover
|
||||
:bordered="false"
|
||||
padding="0">
|
||||
<MarkdownView v-if="item.content"
|
||||
:content="item.content">
|
||||
</MarkdownView>
|
||||
<div v-if="item.type === 'answer'"
|
||||
style="margin-top: 5px; float: right;">
|
||||
Model:
|
||||
<Text strong>{{ item.model }}</Text>
|
||||
<Divider type="vertical"/>
|
||||
Prompt Tokens:
|
||||
<CountUp :end="item.promptTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
<Divider type="vertical"/>
|
||||
Completion Tokens:
|
||||
<CountUp :end="item.completionTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
<Divider type="vertical"/>
|
||||
Total Tokens:
|
||||
<CountUp :end="item.totalTokens"
|
||||
v-font="24">
|
||||
</CountUp>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<CircularLoading :show="loadingMessages">
|
||||
</CircularLoading>
|
||||
</div>
|
||||
</Content>
|
||||
<Divider></Divider>
|
||||
<Footer style="background-color: #FFFFFF;">
|
||||
<Row>
|
||||
<Col span="20">
|
||||
<Input v-model="questionContext"
|
||||
type="textarea"
|
||||
:disabled="sendMessage"
|
||||
:autosize="{minRows: 2,maxRows: 5}">
|
||||
</Input>
|
||||
</Col>
|
||||
<Col span="2" offset="1">
|
||||
<Button type="primary"
|
||||
icon="md-send"
|
||||
:disabled="!questionContext"
|
||||
:loading="sendMessage"
|
||||
@click="handlerSendMessage()">
|
||||
{{ $t('common.send') }}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Footer>
|
||||
</Layout>
|
||||
</Card>
|
||||
<Card v-else
|
||||
dis-hover>
|
||||
<div style="text-align:center; margin: 248px 0px;">
|
||||
No selection chat
|
||||
</div>
|
||||
</Card>
|
||||
</Content>
|
||||
</Layout>
|
||||
<CreateChat v-if="createChatVisible"
|
||||
:is-visible="createChatVisible"
|
||||
:user-id="userInfo.id"
|
||||
@close="handlerCreateChat(false)">
|
||||
</CreateChat>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {defineComponent} from 'vue';
|
||||
import UserService from "@/services/UserService";
|
||||
import {ThirdConfigure, User, UserAnswer, UserQuestion, UserQuestionItem} from '@/model/User';
|
||||
import {VMarkdownView} from 'vue3-markdown'
|
||||
import 'vue3-markdown/dist/style.css'
|
||||
import {InputNumber} from "view-ui-plus";
|
||||
import CreateChat from "@/views/common/chat/components/CreateChat.vue";
|
||||
import ChatService from '@/services/ChatService';
|
||||
import {Filter} from '@/model/Filter';
|
||||
import {AuthResponse} from '@/model/AuthResponse';
|
||||
import {TokenCommon} from '@/common/TokenCommon';
|
||||
import CircularLoading from "@/components/loading/CircularLoading.vue";
|
||||
import MessageService from "@/services/MessageService";
|
||||
import MarkdownView from "@/components/markdown/MarkdownView.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: {InputNumber, VMarkdownView},
|
||||
components: {MarkdownView, CircularLoading, CreateChat},
|
||||
created()
|
||||
{
|
||||
this.handlerInitialize()
|
||||
@ -128,88 +173,82 @@ export default defineComponent({
|
||||
data()
|
||||
{
|
||||
return {
|
||||
loading: false,
|
||||
visibleModel: false,
|
||||
startChatLoading: false,
|
||||
userInfo: null as User,
|
||||
userQuestionContext: null,
|
||||
userQuestionItems: null as UserQuestionItem[],
|
||||
gptModel: 'gpt-3.5-turbo-0613',
|
||||
models: ['gpt-3.5-turbo', 'gpt-3.5-turbo-0301', 'gpt-3.5-turbo-0613', 'gpt-3.5-turbo-16k', 'gpt-3.5-turbo-16k-0613', 'gpt-4', 'gpt-4-0314', 'gpt-4-0613']
|
||||
chats: [],
|
||||
loadingChats: false,
|
||||
selectedChat: null,
|
||||
userInfo: null as AuthResponse,
|
||||
messages: [],
|
||||
loadingMessages: false,
|
||||
createChatVisible: false,
|
||||
questionContext: null,
|
||||
sendMessage: false,
|
||||
promptTokens: 0,
|
||||
completionTokens: 0,
|
||||
totalTokens: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
this.userQuestionItems = [];
|
||||
this.loading = true;
|
||||
UserService.getInfo()
|
||||
this.userInfo = TokenCommon.getAuthUser()
|
||||
this.loadingChats = true;
|
||||
const filter = new Filter();
|
||||
filter.size = 100
|
||||
filter.orders = [{column: 'createTime', order: 'desc'}];
|
||||
ChatService.getAll(filter)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
this.userInfo = response.data;
|
||||
if (this.userInfo.thirdConfigure) {
|
||||
this.userInfo.thirdConfigure = JSON.parse(this.userInfo.thirdConfigure);
|
||||
}
|
||||
else {
|
||||
this.userInfo.thirdConfigure = new ThirdConfigure();
|
||||
}
|
||||
}
|
||||
this.chats = response.data?.content
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
this.loadingChats = false;
|
||||
});
|
||||
},
|
||||
handlerVisibleDetail(value: boolean)
|
||||
handlerCreateChat(opened: boolean)
|
||||
{
|
||||
this.visibleModel = value;
|
||||
if (!value) {
|
||||
this.handlerInitialize();
|
||||
this.createChatVisible = opened;
|
||||
if (!opened) {
|
||||
this.handlerInitialize()
|
||||
}
|
||||
},
|
||||
handlerSave()
|
||||
handlerChangeChat()
|
||||
{
|
||||
UserService.changeThirdConfigure(this.userInfo.thirdConfigure)
|
||||
this.loadingMessages = true;
|
||||
ChatService.getMessages(this.selectedChat.id)
|
||||
.then(response => {
|
||||
this.$Message.success(response.message);
|
||||
this.handlerVisibleDetail(false);
|
||||
this.messages = response.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
this.loadingMessages = false;
|
||||
this.counterToken()
|
||||
this.handlerGoBottom()
|
||||
});
|
||||
},
|
||||
handlerStartChat()
|
||||
handlerSendMessage()
|
||||
{
|
||||
const userQuestion = new UserQuestion();
|
||||
userQuestion.type = 'ChatGPT';
|
||||
userQuestion.content = this.userQuestionContext;
|
||||
userQuestion.from = 'chat';
|
||||
userQuestion.newChat = this.userQuestionItems.length > 0 ? false : true;
|
||||
userQuestion.model = this.gptModel;
|
||||
const answer = new UserAnswer();
|
||||
answer.answer = this.userQuestionContext;
|
||||
const question = new UserQuestionItem();
|
||||
question.content = answer;
|
||||
question.isSelf = true;
|
||||
this.userQuestionItems.push(question);
|
||||
this.handlerGoBottom();
|
||||
this.startChatLoading = true;
|
||||
this.userQuestionContext = null;
|
||||
UserService.startChat(userQuestion)
|
||||
this.sendMessage = true;
|
||||
const message = {
|
||||
content: this.questionContext,
|
||||
user: this.userInfo,
|
||||
chat: this.selectedChat,
|
||||
type: 'question'
|
||||
}
|
||||
this.messages.push(message)
|
||||
this.handlerGoBottom()
|
||||
this.questionContext = null;
|
||||
MessageService.saveOrUpdate(message)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
const answer = new UserQuestionItem();
|
||||
answer.content = response.data;
|
||||
answer.isSelf = false;
|
||||
this.userQuestionItems.push(answer);
|
||||
this.handlerGoBottom();
|
||||
this.messages.push(response.data)
|
||||
}
|
||||
else {
|
||||
this.$Message.error(response.message);
|
||||
this.$Message.error(response.message)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.startChatLoading = false;
|
||||
});
|
||||
this.sendMessage = false
|
||||
this.counterToken()
|
||||
this.handlerGoBottom()
|
||||
})
|
||||
},
|
||||
handlerGoBottom()
|
||||
{
|
||||
@ -217,12 +256,16 @@ export default defineComponent({
|
||||
setTimeout(() => {
|
||||
scrollElem.scrollTo({top: scrollElem.scrollHeight, behavior: 'smooth'});
|
||||
}, 0);
|
||||
},
|
||||
counterToken()
|
||||
{
|
||||
const answers = this.messages.filter(message => message.type === 'answer')
|
||||
this.promptTokens = answers.reduce((sum, message) => sum + message.promptTokens, 0)
|
||||
this.completionTokens = answers.reduce((sum, message) => sum + message.completionTokens, 0)
|
||||
this.totalTokens = answers.reduce((sum, message) => sum + message.totalTokens, 0)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.content {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
|
104
core/datacap-web/src/views/common/chat/components/CreateChat.vue
Normal file
104
core/datacap-web/src/views/common/chat/components/CreateChat.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<Modal v-model="visible"
|
||||
:title="$t('common.create') + $t('common.chat')"
|
||||
width="30%"
|
||||
:closable="false"
|
||||
:mask-closable="false"
|
||||
@cancel="handlerCancel()">
|
||||
<Form :model="fromState">
|
||||
<FormItem :label="$t('common.name')" prop="name">
|
||||
<Input v-model="fromState['name']"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$t('common.avatar')" prop="avatar">
|
||||
<Input v-model="fromState['avatar']"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$t('common.description')" prop="description">
|
||||
<Input v-model="fromState['description']"
|
||||
type="textarea"
|
||||
:rows="2">
|
||||
</Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<Button key="cancel" type="error" :disabled="saving" size="small" @click="handlerCancel()">
|
||||
{{ $t('common.cancel') }}
|
||||
</Button>
|
||||
<Button type="primary" size="small" :loading="saving" @click="handlerSave()">
|
||||
{{ $t('common.save') }}
|
||||
</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {defineComponent} from "vue";
|
||||
import defaultEntity from "@/entity/CommonEntity";
|
||||
import RoomService from "@/services/ChatService";
|
||||
|
||||
export default defineComponent({
|
||||
name: "CreateChat",
|
||||
props: {
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
userId: {
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
saving: false,
|
||||
fromState: null
|
||||
}
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.fromState = defaultEntity.set('name', null)
|
||||
.set('avatar', null)
|
||||
.set('description', null)
|
||||
.set('user', null)
|
||||
.build()
|
||||
.get()
|
||||
},
|
||||
methods: {
|
||||
handlerSave()
|
||||
{
|
||||
this.saving = true;
|
||||
this.fromState['user'] = {
|
||||
id: this.userId
|
||||
}
|
||||
RoomService.saveOrUpdate(this.fromState)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
this.$Message.success("successful");
|
||||
this.handlerCancel();
|
||||
}
|
||||
else {
|
||||
this.$Message.error(response.message);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.saving = false;
|
||||
});
|
||||
},
|
||||
handlerCancel()
|
||||
{
|
||||
this.fromState = null;
|
||||
this.visible = false;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get(): boolean
|
||||
{
|
||||
return this.isVisible;
|
||||
},
|
||||
set(value: boolean)
|
||||
{
|
||||
this.$emit('close', value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -26,6 +26,7 @@ import {User, UserQuestion} from "@/model/User";
|
||||
import {VMarkdownView} from 'vue3-markdown'
|
||||
import 'vue3-markdown/dist/style.css'
|
||||
import {Skeleton} from "view-ui-plus";
|
||||
import MessageService from "@/services/MessageService";
|
||||
|
||||
export default defineComponent({
|
||||
name: 'QueryAiHelp',
|
||||
@ -92,10 +93,10 @@ export default defineComponent({
|
||||
userQuestion.engine = this.engine;
|
||||
userQuestion.error = this.error;
|
||||
userQuestion.locale = this.$i18n.locale;
|
||||
UserService.startChat(userQuestion)
|
||||
MessageService.aiReply(userQuestion)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
this.finalContent = response.data.answer;
|
||||
this.finalContent = response.data.content;
|
||||
}
|
||||
else {
|
||||
this.$Message.error(response.message);
|
||||
|
@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card style="width:100%; minHeight: 150px;">
|
||||
<Card
|
||||
dis-hover
|
||||
style="width:100%; minHeight: 150px;">
|
||||
<template #title>
|
||||
{{ $t('setting.accountSetting') }}
|
||||
</template>
|
||||
@ -20,6 +22,11 @@
|
||||
{{ $t('setting.changePassword') }}
|
||||
</Button>
|
||||
</FormItem>
|
||||
<FormItem :label="$t('common.chatgpt')">
|
||||
<Button type="text" style="float: right;" @click="handlerChatGPT(true)">
|
||||
{{ $t('setting.changeChatGpt') }}
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Content>
|
||||
</Layout>
|
||||
@ -43,7 +50,14 @@
|
||||
<Button type="primary" :loading="loading" @click="handlerChangePassword()">{{ $t('common.save') }}</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
<ChangeUsername v-if="changeUsername" :isVisible="changeUsername" @close="changeUsername = false"/>
|
||||
<ChangeUsername v-if="changeUsername"
|
||||
:isVisible="changeUsername"
|
||||
@close="changeUsername = false">
|
||||
</ChangeUsername>
|
||||
<ChangeChatGpt v-if="changeChatGpt"
|
||||
:is-visible="changeChatGpt"
|
||||
@close="handlerChatGPT(false)">
|
||||
</ChangeChatGpt>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
@ -53,9 +67,10 @@ import {UserPassword} from "@/model/UserPassword";
|
||||
import Common from "@/common/Common";
|
||||
import router from "@/router";
|
||||
import ChangeUsername from "@/views/user/profile/components/ChangeUsername.vue";
|
||||
import ChangeChatGpt from "@/views/user/profile/components/ChangeChatGpt.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: {ChangeUsername},
|
||||
components: {ChangeChatGpt, ChangeUsername},
|
||||
setup()
|
||||
{
|
||||
const formState = reactive<UserPassword>({
|
||||
@ -72,6 +87,7 @@ export default defineComponent({
|
||||
return {
|
||||
changePasswordVisible: false,
|
||||
changeUsername: false,
|
||||
changeChatGpt: false,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
@ -107,6 +123,10 @@ export default defineComponent({
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handlerChatGPT(opened: boolean)
|
||||
{
|
||||
this.changeChatGpt = opened
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div>
|
||||
<Modal v-model="visible"
|
||||
:title="$t('common.chatgpt')"
|
||||
:closable="false"
|
||||
:mask-closable="false"
|
||||
@cancel="handlerCancel()">
|
||||
<Form :model="chatConfigure"
|
||||
:label-width="100">
|
||||
<FormItem prop="host"
|
||||
:label="$t('common.proxy')">
|
||||
<Input type="text"
|
||||
v-model="chatConfigure.host">
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem name="token"
|
||||
:label="$t('common.token')">
|
||||
<Input type="password"
|
||||
v-model="chatConfigure.token">
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem name="timeout"
|
||||
:label="$t('common.timeout')">
|
||||
<InputNumber v-model="chatConfigure.timeout"
|
||||
min="1">
|
||||
</InputNumber>
|
||||
</FormItem>
|
||||
<FormItem name="contentCount"
|
||||
:label="$t('setting.contentCount')">
|
||||
<InputNumber v-model="chatConfigure.contentCount"
|
||||
min="1"
|
||||
max="10">
|
||||
</InputNumber>
|
||||
</FormItem>
|
||||
<CircularLoading v-if="loadingUserInfo"
|
||||
:show="loadingUserInfo">
|
||||
</CircularLoading>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<Button danger
|
||||
@click="handlerCancel">
|
||||
{{ $t('common.cancel') }}
|
||||
</Button>
|
||||
<Button type="primary"
|
||||
:loading="loadingChange"
|
||||
@click="handlerSave()">
|
||||
{{ $t('common.save') }}
|
||||
</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {defineComponent} from 'vue';
|
||||
import UserService from "@/services/UserService";
|
||||
import CircularLoading from "@/components/loading/CircularLoading.vue";
|
||||
import {ThirdConfigure} from "@/model/User";
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ChangeChatGpt',
|
||||
components: {CircularLoading},
|
||||
props: {
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
loadingUserInfo: false,
|
||||
loadingChange: false,
|
||||
chatConfigure: {} as ThirdConfigure
|
||||
}
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.handlerInitialize()
|
||||
},
|
||||
methods: {
|
||||
handlerInitialize()
|
||||
{
|
||||
this.loadingUserInfo = true
|
||||
UserService.getInfo()
|
||||
.then(response => {
|
||||
if (response.data.chatConfigure) {
|
||||
this.chatConfigure = JSON.parse(response.data.chatConfigure)
|
||||
}
|
||||
else {
|
||||
this.chatConfigure = new ThirdConfigure()
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loadingUserInfo = false
|
||||
})
|
||||
},
|
||||
handlerSave()
|
||||
{
|
||||
this.loadingChange = true;
|
||||
UserService.changeThirdConfigure(this.chatConfigure)
|
||||
.then((response) => {
|
||||
if (response.status) {
|
||||
this.$Message.success('Success');
|
||||
this.handlerCancel()
|
||||
}
|
||||
else {
|
||||
this.$Message.error(response.message);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loadingChange = false;
|
||||
});
|
||||
},
|
||||
handlerCancel()
|
||||
{
|
||||
this.visible = false;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
visible: {
|
||||
get(): boolean
|
||||
{
|
||||
return this.isVisible;
|
||||
},
|
||||
set(value: boolean)
|
||||
{
|
||||
this.$emit('close', value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.content {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user