Skip to content

Commit

Permalink
feat: vision model (#489)
Browse files Browse the repository at this point in the history
* mongo init

* perf: mongo connect

* perf: tts

perf: whisper and tts

peref: tts whisper permission

log

reabase (#488)

* perf: modal

* i18n

* perf: schema lean

* feat: vision model format

* perf: tts loading

* perf: static data

* perf: tts

* feat: image

* perf: image

* perf: upload image and title

* perf: image size

* doc

* perf: color

* doc

* speaking can not select file

* doc
  • Loading branch information
c121914yu authored Nov 18, 2023
1 parent 70f3373 commit c5664c7
Show file tree
Hide file tree
Showing 58 changed files with 648 additions and 252 deletions.
15 changes: 15 additions & 0 deletions docSite/content/docs/development/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ weight: 520
"quoteMaxToken": 2000, // 最大引用内容长度
"maxTemperature": 1.2, // 最大温度值
"censor": false, // 是否开启敏感词过滤(商业版)
"vision": false, // 支持图片输入
"defaultSystemChatPrompt": ""
},
{
Expand All @@ -47,6 +48,7 @@ weight: 520
"quoteMaxToken": 8000,
"maxTemperature": 1.2,
"censor": false,
"vision": false,
"defaultSystemChatPrompt": ""
},
{
Expand All @@ -58,6 +60,19 @@ weight: 520
"quoteMaxToken": 4000,
"maxTemperature": 1.2,
"censor": false,
"vision": false,
"defaultSystemChatPrompt": ""
},
{
"model": "gpt-4-vision-preview",
"name": "GPT4-Vision",
"maxContext": 128000,
"maxResponse": 4000,
"price": 0,
"quoteMaxToken": 100000,
"maxTemperature": 1.2,
"censor": false,
"vision": true,
"defaultSystemChatPrompt": ""
}
],
Expand Down
16 changes: 16 additions & 0 deletions docSite/content/docs/installation/upgrading/461.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: 'V4.6.1'
description: 'FastGPT V4.6 .1'
icon: 'upgrade'
draft: false
toc: true
weight: 835
---


## V4.6.1 功能介绍

1. 新增 - GPT4-v 模型支持
2. 新增 - whisper 语音输入
3. 优化 - TTS 流传输
4. 优化 - TTS 缓存
2 changes: 1 addition & 1 deletion packages/global/common/string/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const simpleText = (text: string) => {
};

/*
replace {{variable}} to value
replace {{variable}} to value
*/
export function replaceVariable(text: string, obj: Record<string, string | number>) {
for (const key in obj) {
Expand Down
1 change: 1 addition & 0 deletions packages/global/core/ai/model.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type ChatModelItemType = LLMModelItemType & {
quoteMaxToken: number;
maxTemperature: number;
censor?: boolean;
vision?: boolean;
defaultSystemChatPrompt?: string;
};

Expand Down
15 changes: 15 additions & 0 deletions packages/global/core/ai/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const defaultChatModels: ChatModelItemType[] = [
quoteMaxToken: 2000,
maxTemperature: 1.2,
censor: false,
vision: false,
defaultSystemChatPrompt: ''
},
{
Expand All @@ -28,6 +29,7 @@ export const defaultChatModels: ChatModelItemType[] = [
quoteMaxToken: 8000,
maxTemperature: 1.2,
censor: false,
vision: false,
defaultSystemChatPrompt: ''
},
{
Expand All @@ -39,6 +41,19 @@ export const defaultChatModels: ChatModelItemType[] = [
quoteMaxToken: 4000,
maxTemperature: 1.2,
censor: false,
vision: false,
defaultSystemChatPrompt: ''
},
{
model: 'gpt-4-vision-preview',
name: 'GPT4-Vision',
maxContext: 128000,
maxResponse: 4000,
price: 0,
quoteMaxToken: 100000,
maxTemperature: 1.2,
censor: false,
vision: true,
defaultSystemChatPrompt: ''
}
];
Expand Down
6 changes: 4 additions & 2 deletions packages/global/core/ai/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import type {
ChatCompletionMessageParam,
ChatCompletionContentPart
} from 'openai/resources';

export type ChatCompletionContentPart = ChatCompletionContentPart;
export type ChatCompletionCreateParams = ChatCompletionCreateParams;
export type ChatMessageItemType = Omit<ChatCompletionMessageParam> & {
export type ChatMessageItemType = Omit<ChatCompletionMessageParam, 'name'> & {
name?: any;
dataId?: string;
content: any;
};
} & any;

export type ChatCompletion = ChatCompletion;
export type StreamChatType = Stream<ChatCompletionChunk>;
Expand Down
3 changes: 3 additions & 0 deletions packages/global/core/chat/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ export const ChatSourceMap = {

export const HUMAN_ICON = `/icon/human.svg`;
export const LOGO_ICON = `/icon/logo.svg`;

export const IMG_BLOCK_KEY = 'img-block';
export const FILE_BLOCK_KEY = 'file-block';
6 changes: 6 additions & 0 deletions packages/global/core/chat/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IMG_BLOCK_KEY, FILE_BLOCK_KEY } from './constants';

export function chatContentReplaceBlock(content: string = '') {
const regex = new RegExp(`\`\`\`(${IMG_BLOCK_KEY})\\n([\\s\\S]*?)\`\`\``, 'g');
return content.replace(regex, '').trim();
}
1 change: 1 addition & 0 deletions packages/service/common/buffer/tts/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ try {

export const MongoTTSBuffer: Model<TTSBufferSchemaType> =
models[collectionName] || model(collectionName, TTSBufferSchema);
MongoTTSBuffer.syncIndexes();
20 changes: 17 additions & 3 deletions packages/service/common/file/image/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,26 @@ export function getMongoImgUrl(id: string) {
return `${imageBaseUrl}${id}`;
}

export async function uploadMongoImg({ base64Img, userId }: { base64Img: string; userId: string }) {
export const maxImgSize = 1024 * 1024 * 12;
export async function uploadMongoImg({
base64Img,
teamId,
expiredTime
}: {
base64Img: string;
teamId: string;
expiredTime?: Date;
}) {
if (base64Img.length > maxImgSize) {
return Promise.reject('Image too large');
}

const base64Data = base64Img.split(',')[1];

const { _id } = await MongoImage.create({
userId,
binary: Buffer.from(base64Data, 'base64')
teamId,
binary: Buffer.from(base64Data, 'base64'),
expiredTime
});

return getMongoImgUrl(String(_id));
Expand Down
19 changes: 15 additions & 4 deletions packages/service/common/file/image/schema.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
import { connectionMongo, type Model } from '../../mongo';
const { Schema, model, models } = connectionMongo;

const ImageSchema = new Schema({
userId: {
teamId: {
type: Schema.Types.ObjectId,
ref: 'user',
required: true
ref: TeamCollectionName
},
binary: {
type: Buffer
},
expiredTime: {
type: Date
}
});

export const MongoImage: Model<{ userId: string; binary: Buffer }> =
try {
ImageSchema.index({ expiredTime: 1 }, { expireAfterSeconds: 60 });
} catch (error) {
console.log(error);
}

export const MongoImage: Model<{ teamId: string; binary: Buffer }> =
models['image'] || model('image', ImageSchema);

MongoImage.syncIndexes();
2 changes: 2 additions & 0 deletions packages/service/core/app/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,5 @@ try {

export const MongoApp: Model<AppType> =
models[appCollectionName] || model(appCollectionName, AppSchema);

MongoApp.syncIndexes();
2 changes: 2 additions & 0 deletions packages/service/core/chat/chatItemSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,5 @@ try {

export const MongoChatItem: Model<ChatItemType> =
models['chatItem'] || model('chatItem', ChatItemSchema);

MongoChatItem.syncIndexes();
3 changes: 2 additions & 1 deletion packages/service/core/chat/chatSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const ChatSchema = new Schema({
});

try {
ChatSchema.index({ userId: 1 });
ChatSchema.index({ tmbId: 1 });
ChatSchema.index({ updateTime: -1 });
ChatSchema.index({ appId: 1 });
} catch (error) {
Expand All @@ -101,3 +101,4 @@ try {

export const MongoChat: Model<ChatType> =
models[chatCollectionName] || model(chatCollectionName, ChatSchema);
MongoChat.syncIndexes();
101 changes: 100 additions & 1 deletion packages/service/core/chat/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { ChatItemType } from '@fastgpt/global/core/chat/type.d';
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { ChatRoleEnum, IMG_BLOCK_KEY } from '@fastgpt/global/core/chat/constants';
import { countMessagesTokens, countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
import { adaptRole_Chat2Message } from '@fastgpt/global/core/chat/adapt';
import type { ChatCompletionContentPart } from '@fastgpt/global/core/ai/type.d';

/* slice chat context by tokens */
export function ChatContextFilter({
Expand Down Expand Up @@ -51,3 +52,101 @@ export function ChatContextFilter({

return [...systemPrompts, ...chats];
}

/**
string to vision model. Follow the markdown code block rule for interception:
@rule:
```img-block
{src:""}
{src:""}
```
```file-block
{name:"",src:""},
{name:"",src:""}
```
@example:
What’s in this image?
```img-block
{src:"https://1.png"}
```
@return
[
{ type: 'text', text: 'What’s in this image?' },
{
type: 'image_url',
image_url: {
url: 'https://1.png'
}
}
]
*/
export function formatStr2ChatContent(str: string) {
const content: ChatCompletionContentPart[] = [];
let lastIndex = 0;
const regex = new RegExp(`\`\`\`(${IMG_BLOCK_KEY})\\n([\\s\\S]*?)\`\`\``, 'g');

let match;

while ((match = regex.exec(str)) !== null) {
// add previous text
if (match.index > lastIndex) {
const text = str.substring(lastIndex, match.index).trim();
if (text) {
content.push({ type: 'text', text });
}
}

const blockType = match[1].trim();

if (blockType === IMG_BLOCK_KEY) {
const blockContentLines = match[2].trim().split('\n');
const jsonLines = blockContentLines.map((item) => {
try {
return JSON.parse(item) as { src: string };
} catch (error) {
return { src: '' };
}
});

for (const item of jsonLines) {
if (!item.src) throw new Error("image block's content error");
}

content.push(
...jsonLines.map((item) => ({
type: 'image_url' as any,
image_url: {
url: item.src
}
}))
);
}

lastIndex = regex.lastIndex;
}

// add remaining text
if (lastIndex < str.length) {
const remainingText = str.substring(lastIndex).trim();
if (remainingText) {
content.push({ type: 'text', text: remainingText });
}
}

// Continuous text type content, if type=text, merge them
for (let i = 0; i < content.length - 1; i++) {
const currentContent = content[i];
const nextContent = content[i + 1];
if (currentContent.type === 'text' && nextContent.type === 'text') {
currentContent.text += nextContent.text;
content.splice(i + 1, 1);
i--;
}
}

if (content.length === 1 && content[0].type === 'text') {
return content[0].text;
}
return content ? content : null;
}
6 changes: 3 additions & 3 deletions packages/service/core/dataset/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ export async function findDatasetIdTreeByTopDatasetId(
}

export async function getCollectionWithDataset(collectionId: string) {
const data = (
await MongoDatasetCollection.findById(collectionId).populate('datasetId')
)?.toJSON() as CollectionWithDatasetType;
const data = (await MongoDatasetCollection.findById(collectionId)
.populate('datasetId')
.lean()) as CollectionWithDatasetType;
if (!data) {
return Promise.reject('Collection is not exist');
}
Expand Down
1 change: 1 addition & 0 deletions packages/service/core/dataset/data/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ try {

export const MongoDatasetData: Model<DatasetDataSchemaType> =
models[DatasetDataCollectionName] || model(DatasetDataCollectionName, DatasetDataSchema);
MongoDatasetData.syncIndexes();
1 change: 1 addition & 0 deletions packages/service/core/dataset/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@ try {

export const MongoDataset: Model<DatasetSchemaType> =
models[DatasetCollectionName] || model(DatasetCollectionName, DatasetSchema);
MongoDataset.syncIndexes();
2 changes: 2 additions & 0 deletions packages/service/core/dataset/training/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,5 @@ try {

export const MongoDatasetTraining: Model<DatasetTrainingSchemaType> =
models[DatasetTrainingCollectionName] || model(DatasetTrainingCollectionName, TrainingDataSchema);

MongoDatasetTraining.syncIndexes();
3 changes: 2 additions & 1 deletion packages/service/core/plugin/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ const PluginSchema = new Schema({
});

try {
PluginSchema.index({ userId: 1 });
PluginSchema.index({ tmbId: 1 });
} catch (error) {
console.log(error);
}

export const MongoPlugin: Model<PluginItemSchema> =
models[ModuleCollectionName] || model(ModuleCollectionName, PluginSchema);
MongoPlugin.syncIndexes();
1 change: 1 addition & 0 deletions packages/service/support/activity/promotion/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ const PromotionRecordSchema = new Schema({

export const MongoPromotionRecord: Model<PromotionRecordType> =
models['promotionRecord'] || model('promotionRecord', PromotionRecordSchema);
MongoPromotionRecord.syncIndexes();
1 change: 1 addition & 0 deletions packages/service/support/openapi/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ const OpenApiSchema = new Schema(

export const MongoOpenApi: Model<OpenApiSchema> =
models['openapi'] || model('openapi', OpenApiSchema);
MongoOpenApi.syncIndexes();
2 changes: 2 additions & 0 deletions packages/service/support/outLink/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,5 @@ const OutLinkSchema = new Schema({

export const MongoOutLink: Model<SchemaType> =
models['outlinks'] || model('outlinks', OutLinkSchema);

MongoOutLink.syncIndexes();
Loading

0 comments on commit c5664c7

Please sign in to comment.