diff --git a/backend/api/conf/config.py b/backend/api/conf/config.py index 87998e71..ea6fa9b9 100644 --- a/backend/api/conf/config.py +++ b/backend/api/conf/config.py @@ -44,6 +44,7 @@ class DataSetting(BaseModel): data_dir: str = './data' database_url: str = 'sqlite+aiosqlite:///data/database.db' mongodb_url: str = 'mongodb://cws:password@mongo:27017' # 'mongodb://cws:password@localhost:27017' + mongodb_db_name: str = 'cws' run_migration: bool = False max_file_upload_size: int = Field(100 * 1024 * 1024, ge=0) @@ -66,7 +67,7 @@ class OpenaiWebChatGPTSetting(BaseModel): is_plus_account: bool = True chatgpt_base_url: Optional[str] = None proxy: Optional[str] = None - common_timeout: int = Field(10, ge=1) # connect, read, write + common_timeout: int = Field(20, ge=1) # connect, read, write ask_timeout: int = Field(600, ge=1) sync_conversations_on_startup: bool = True sync_conversations_schedule: bool = False @@ -75,6 +76,8 @@ class OpenaiWebChatGPTSetting(BaseModel): "gpt_4_browsing"] model_code_mapping: dict[OpenaiWebChatModels, str] = default_openai_web_model_code_mapping file_upload_strategy: OpenaiWebFileUploadStrategyOption = OpenaiWebFileUploadStrategyOption.browser_upload_only + enable_uploading_attachments: bool = True + enable_uploading_multimodal_images: bool = True @validator("chatgpt_base_url") def chatgpt_base_url_end_with_slash(cls, v): diff --git a/backend/api/database/mongodb.py b/backend/api/database/mongodb.py index 836df453..aa258cd0 100644 --- a/backend/api/database/mongodb.py +++ b/backend/api/database/mongodb.py @@ -9,18 +9,18 @@ logger = get_logger(__name__) config = Config() -DATABASE_NAME = "cws" + client: AsyncIOMotorClient | None = None async def init_mongodb(): global client client = AsyncIOMotorClient(config.data.mongodb_url) - await init_beanie(database=client[DATABASE_NAME], + await init_beanie(database=client[config.data.mongodb_db_name], document_models=[OpenaiApiConversationHistoryDocument, OpenaiWebConversationHistoryDocument, AskLogDocument, RequestLogDocument]) # 展示当前mongodb数据库用量 - db = client[DATABASE_NAME] + db = client[config.data.mongodb_db_name] stats = await db.command({"dbStats": 1}) logger.info( f"MongoDB initialized. dataSize: {stats['dataSize'] / 1024 / 1024:.2f} MB, objects: {stats['objects']}") @@ -34,7 +34,7 @@ async def handle_timeseries(): """ global client assert client is not None, "MongoDB not initialized" - db = client[DATABASE_NAME] + db = client[config.data.mongodb_db_name] time_series_docs = [AskLogDocument, RequestLogDocument] config_ttls = [config.stats.ask_stats_ttl, config.stats.request_stats_ttl] for doc, config_ttl in zip(time_series_docs, config_ttls): diff --git a/backend/api/enums/options.py b/backend/api/enums/options.py index 0c19e7b9..b8038d3b 100644 --- a/backend/api/enums/options.py +++ b/backend/api/enums/options.py @@ -3,7 +3,6 @@ class OpenaiWebFileUploadStrategyOption(StrEnum): - disable_upload = auto() server_upload_only = auto() browser_upload_only = auto() browser_upload_when_file_size_exceed = auto() diff --git a/backend/api/file_provider.py b/backend/api/file_provider.py index de187046..87e7423e 100644 --- a/backend/api/file_provider.py +++ b/backend/api/file_provider.py @@ -31,6 +31,7 @@ async def save_file(self, file: UploadFile, user_id: int, session: AsyncSession) if not file_dir_path.exists(): file_dir_path.mkdir(parents=True) + async with aiofiles.open(file_path, "wb") as buffer: while True: chunk = await file.read(1024 * 1024) # read by 1MB chunk diff --git a/backend/api/models/json.py b/backend/api/models/json.py index db125c44..ae449304 100644 --- a/backend/api/models/json.py +++ b/backend/api/models/json.py @@ -1,5 +1,5 @@ import datetime -from typing import Optional, Generic, TypeVar, get_args +from typing import Optional, Generic, TypeVar, get_args, Literal from pydantic import BaseModel, Field, create_model, root_validator from pydantic.generics import GenericModel @@ -57,5 +57,6 @@ class CustomOpenaiApiSettings(BaseModel): class UploadedFileOpenaiWebInfo(BaseModel): file_id: Optional[str] + use_case: Optional[Literal['ace_upload', 'multimodal'] | str] upload_url: Optional[str] = Field(description="上传文件的url, 上传后应清空该字段") download_url: Optional[str] diff --git a/backend/api/routers/chat.py b/backend/api/routers/chat.py index 4d663fd1..447b61de 100644 --- a/backend/api/routers/chat.py +++ b/backend/api/routers/chat.py @@ -209,9 +209,15 @@ async def check_limits(user: UserReadAdmin, ask_request: AskRequest): # 判断是否允许使用附件 if ask_request.openai_web_attachments and len(ask_request.openai_web_attachments) > 0: if ask_request.model != OpenaiWebChatModels.gpt_4_code_interpreter or \ - config.openai_web.file_upload_strategy == OpenaiWebFileUploadStrategyOption.disable_upload: + config.openai_web.enable_uploading_attachments is False: raise WebsocketInvalidAskException("errors.attachmentsNotAllowed") + # 判断是否允许使用多模态图片 + if ask_request.openai_web_multimodal_image_parts and len(ask_request.openai_web_multimodal_image_parts) > 0: + if ask_request.model != OpenaiWebChatModels.gpt_4 or \ + config.openai_web.enable_uploading_multimodal_images is False: + raise WebsocketInvalidAskException("errors.multimodalImagesNotAllowed") + def check_message(msg: str): # 检查消息中的敏感信息 @@ -282,7 +288,7 @@ async def reply(response: AskResponse): queueing_start_time = None queueing_end_time = None - # rev: 排队 + # 排队 if ask_request.source == ChatSourceTypes.openai_web: if openai_web_manager.is_busy(): await reply(AskResponse( @@ -324,12 +330,14 @@ async def reply(response: AskResponse): model = OpenaiApiChatModels(ask_request.model) # stream 传输 - async for data in manager.ask(content=ask_request.content, + async for data in manager.ask(text_content=ask_request.text_content, conversation_id=ask_request.conversation_id, parent_id=ask_request.parent, model=model, plugin_ids=ask_request.openai_web_plugin_ids, - attachments=ask_request.openai_web_attachments): + attachments=ask_request.openai_web_attachments, + multimodal_image_parts=ask_request.openai_web_multimodal_image_parts, + ): has_got_reply = True try: @@ -449,7 +457,7 @@ async def reply(response: AskResponse): if ask_request.source == ChatSourceTypes.openai_api: assert message.parent is not None, "message.parent is None" - content = ask_request.content + content = ask_request.text_content if isinstance(content, str): content = OpenaiApiChatMessageTextContent(content_type="text", text=content) @@ -508,11 +516,11 @@ async def reply(response: AskResponse): if ask_request.new_conversation: assert conversation_id is not None, "has_got_reply but conversation_id is None" - # rev设置默认标题 - if ask_request.source == ChatSourceTypes.openai_web: + # 设置默认标题 + if ask_request.source == ChatSourceTypes.openai_web and ask_request.new_title is not None and \ + ask_request.new_title.strip() != "": try: - if ask_request.new_title is not None: - await openai_web_manager.set_conversation_title(str(conversation_id), ask_request.new_title) + await openai_web_manager.set_conversation_title(str(conversation_id), ask_request.new_title) except Exception as e: logger.warning(f"set_conversation_title error {e.__class__.__name__}: {str(e)}") diff --git a/backend/api/routers/conv.py b/backend/api/routers/conv.py index e5957448..52b542d0 100644 --- a/backend/api/routers/conv.py +++ b/backend/api/routers/conv.py @@ -200,22 +200,19 @@ async def delete_all_conversation(_user: User = Depends(current_super_user)): return response(200) -@router.patch("/conv/{conversation_id}/gen_title", tags=["conversation"], response_model=OpenaiWebConversationSchema) +@router.patch("/conv/{conversation_id}/gen_title", tags=["conversation"], response_model=str) async def generate_conversation_title(message_id: str, conversation: OpenaiWebConversation = Depends(_get_conversation_by_id)): - if conversation.title is not None: - raise InvalidParamsException("errors.conversationTitleAlreadyGenerated") async with get_async_session_context() as session: - result = await openai_web_manager.generate_conversation_title(conversation.id, message_id) - if result["title"]: - conversation.title = result["title"] + title = await openai_web_manager.generate_conversation_title(conversation.conversation_id, message_id) + if title: + conversation.title = title session.add(conversation) await session.commit() await session.refresh(conversation) else: - raise InvalidParamsException(f"{result['message']}") - result = jsonable_encoder(conversation) - return result + raise InternalException("errors.generateTitleFailed") + return title @router.get("/conv/{conversation_id}/interpreter", tags=["conversation"], response_model=OpenaiChatInterpreterInfo) @@ -224,12 +221,6 @@ async def get_conversation_interpreter_info(conversation_id: str): return response(200, result=url) -@router.get("/conv/files/{file_id}/download-url", tags=["conversation"]) -async def get_file_download_url(file_id: str): - url = await openai_web_manager.get_file_download_url(file_id) - return response(200, result=url) - - @router.get("/conv/{conversation_id}/interpreter/download-url", tags=["conversation"]) async def get_conversation_interpreter_download_url(conversation_id: str, message_id: str, sandbox_path: str): if message_id is None or sandbox_path is None: diff --git a/backend/api/routers/files.py b/backend/api/routers/files.py index dd7d4108..028575af 100644 --- a/backend/api/routers/files.py +++ b/backend/api/routers/files.py @@ -3,6 +3,7 @@ from mimetypes import guess_type from fastapi import APIRouter, Depends, HTTPException, File, UploadFile +from fastapi_cache.decorator import cache from starlette.responses import FileResponse from api.conf import Config @@ -12,6 +13,7 @@ from api.file_provider import FileProvider from api.models.db import User, UploadedFileInfo from api.models.json import UploadedFileOpenaiWebInfo +from api.schemas import UserRead from api.schemas.file_schemas import UploadedFileInfoSchema, StartUploadResponseSchema from api.schemas.openai_schemas import OpenaiChatFileUploadInfo from api.sources import OpenaiWebChatManager @@ -23,14 +25,23 @@ openai_web_manager = OpenaiWebChatManager() +@router.get("/files/{file_id}/download-url", tags=["conversation"], response_model=str) +@cache(expire=10 * 60) +async def get_file_download_url(file_id: str): + """ + file_id: OpenAI 分配的 id,以 file- 开头 + """ + url = await openai_web_manager.get_file_download_url(file_id) + return url + + @router.post("/files/local/upload", tags=["files"], response_model=UploadedFileInfoSchema) async def upload_file_to_local(file: UploadFile = File(...), user: User = Depends(current_active_user)): """ 上传文件到服务器。文件将被保存在服务器上,返回文件信息。 仅当需要在服务器留存上传的文件时才使用. """ - if config.openai_web.file_upload_strategy in [OpenaiWebFileUploadStrategyOption.browser_upload_only, - OpenaiWebFileUploadStrategyOption.disable_upload]: + if config.openai_web.file_upload_strategy == OpenaiWebFileUploadStrategyOption.browser_upload_only: raise InvalidRequestException(f"File upload disabled") if file.size > config.data.max_file_upload_size: raise InvalidRequestException(f"File too large! Max size: {config.data.max_file_upload_size}") @@ -68,12 +79,17 @@ async def start_upload_to_openai(upload_info: OpenaiChatFileUploadInfo, user: Us b. 再调用 upload_local_file_to_openai_web 接口,通知服务器上传文件到 OpenAI Web """ file_size_exceed = upload_info.file_size > config.data.max_file_upload_size - if upload_info.use_case != "ace_upload": - raise InvalidRequestException(f"Invalid use case: {upload_info.use_case}") if config.openai_web.file_upload_strategy == OpenaiWebFileUploadStrategyOption.server_upload_only and file_size_exceed: - raise InvalidRequestException(f"File too large! Max size: {config.data.max_file_upload_size}") - if config.openai_web.file_upload_strategy == OpenaiWebFileUploadStrategyOption.disable_upload: - raise InvalidRequestException(f"File upload disabled") + raise InvalidRequestException(f"File is too large! Max size: {config.data.max_file_upload_size}") + user_info = UserRead.from_orm(user) + if upload_info.use_case == "ace_upload" and \ + (user_info.setting.openai_web.allow_uploading_attachments is False or + config.openai_web.enable_uploading_attachments is False): + raise InvalidRequestException(f"Uploading attachments disabled") + if upload_info.use_case == "multimodal" and \ + (user_info.setting.openai_web.allow_uploading_multimodal_images is False or + config.openai_web.enable_uploading_multimodal_images is False): + raise InvalidRequestException(f"Uploading multimodal images disabled") file_info = None diff --git a/backend/api/routers/users.py b/backend/api/routers/users.py index 960a5298..ac4d7290 100644 --- a/backend/api/routers/users.py +++ b/backend/api/routers/users.py @@ -17,6 +17,7 @@ get_user_manager, UserManager router = APIRouter() +config = Config() # router.include_router( @@ -93,10 +94,14 @@ async def get_me(user: User = Depends(current_active_user)): user_read = UserRead.from_orm(user) for source in ["openai_api", "openai_web"]: source_setting = getattr(user_read.setting, source) - global_enabled_models = getattr(Config(), source).enabled_models + global_enabled_models = getattr(config, source).enabled_models source_setting.available_models = list( set(source_setting.available_models).intersection(set(global_enabled_models))) setattr(user_read.setting, source, source_setting) + if not config.openai_web.enable_uploading_attachments: + user_read.setting.openai_web.allow_uploading_attachments = False + if not config.openai_web.enable_uploading_multimodal_images: + user_read.setting.openai_web.allow_uploading_multimodal_images = False return user_read diff --git a/backend/api/schemas/conversation_schemas.py b/backend/api/schemas/conversation_schemas.py index f9e4219d..602a641d 100644 --- a/backend/api/schemas/conversation_schemas.py +++ b/backend/api/schemas/conversation_schemas.py @@ -7,7 +7,8 @@ from strenum import StrEnum from api.enums import ChatSourceTypes, OpenaiWebChatModels, OpenaiApiChatModels -from api.models.doc import OpenaiWebChatMessage, OpenaiApiChatMessage +from api.models.doc import OpenaiWebChatMessage, OpenaiApiChatMessage, \ + OpenaiWebChatMessageMultimodalTextContentImagePart from api.schemas.openai_schemas import OpenaiWebAskAttachment from utils.logger import get_logger @@ -29,13 +30,14 @@ class AskRequest(BaseModel): source: ChatSourceTypes model: str new_conversation: bool - new_title: Optional[str] = None + new_title: Optional[str] = None # 为空则生成标题 conversation_id: Optional[uuid.UUID] = None parent: Optional[uuid.UUID] = None api_context_message_count: int = Field(-1, ge=-1) - content: str + text_content: str openai_web_plugin_ids: Optional[list[str]] = None openai_web_attachments: Optional[list[OpenaiWebAskAttachment]] = None + openai_web_multimodal_image_parts: Optional[list[OpenaiWebChatMessageMultimodalTextContentImagePart]] = None @root_validator def check(cls, values): diff --git a/backend/api/schemas/openai_schemas.py b/backend/api/schemas/openai_schemas.py index b6f16502..e5a6077f 100644 --- a/backend/api/schemas/openai_schemas.py +++ b/backend/api/schemas/openai_schemas.py @@ -62,7 +62,7 @@ class OpenaiChatInterpreterInfo(BaseModel): class OpenaiChatFileUploadInfo(BaseModel): file_name: str file_size: int - use_case: str | Literal['ace_upload'] + use_case: Literal['ace_upload', 'multimodal'] class OpenaiChatFileUploadUrlResponse(BaseModel): diff --git a/backend/api/schemas/user_schemas.py b/backend/api/schemas/user_schemas.py index 027b8536..3a86cf13 100644 --- a/backend/api/schemas/user_schemas.py +++ b/backend/api/schemas/user_schemas.py @@ -2,12 +2,15 @@ from typing import Optional from fastapi_users import schemas -from pydantic import BaseModel, EmailStr +from pydantic import BaseModel, EmailStr, validator, root_validator +from api.conf import Config from api.enums import OpenaiWebChatStatus, OpenaiWebChatModels, OpenaiApiChatModels from api.models.json import CustomOpenaiApiSettings, TimeWindowRateLimit, DailyTimeSlot, \ OpenaiWebPerModelAskCount, OpenaiApiPerModelAskCount +config = Config() + class BaseSourceSettingSchema(BaseModel): allow_to_use: bool @@ -45,12 +48,17 @@ def unlimited(): class OpenaiWebSourceSettingSchema(BaseSourceSettingSchema): available_models: list[OpenaiWebChatModels] per_model_ask_count: OpenaiWebPerModelAskCount + allow_uploading_attachments: bool + allow_uploading_multimodal_images: bool @staticmethod def default(): return OpenaiWebSourceSettingSchema( - available_models=[OpenaiWebChatModels(m) for m in OpenaiWebChatModels], + available_models=[OpenaiWebChatModels(m) for m in + ["gpt_3_5", "gpt_4", "gpt_4_code_interpreter", "gpt_4_plugins", "gpt_4_browsing"]], per_model_ask_count=OpenaiWebPerModelAskCount(), + allow_uploading_attachments=config.openai_web.enable_uploading_attachments, + allow_uploading_multimodal_images=config.openai_web.enable_uploading_multimodal_images, **BaseSourceSettingSchema.default().dict() ) @@ -59,9 +67,19 @@ def unlimited(): return OpenaiWebSourceSettingSchema( available_models=[OpenaiWebChatModels(m) for m in OpenaiWebChatModels], per_model_ask_count=OpenaiWebPerModelAskCount.unlimited(), + allow_uploading_attachments=True, + allow_uploading_multimodal_images=True, **BaseSourceSettingSchema.unlimited().dict() ) + @root_validator(pre=True) + def check(cls, values): + if "allow_uploading_attachments" not in values: + values["allow_uploading_attachments"] = config.openai_web.enable_uploading_attachments + if "allow_uploading_multimodal_images" not in values: + values["allow_uploading_multimodal_images"] = config.openai_web.enable_uploading_multimodal_images + return values + class Config: orm_mode = True diff --git a/backend/api/sources/openai_api.py b/backend/api/sources/openai_api.py index cf4223d5..fb206ff5 100644 --- a/backend/api/sources/openai_api.py +++ b/backend/api/sources/openai_api.py @@ -60,7 +60,7 @@ def __init__(self): def reset_session(self): self.session = make_session() - async def ask(self, content: str, conversation_id: uuid.UUID = None, + async def ask(self, text_content: str, conversation_id: uuid.UUID = None, parent_id: uuid.UUID = None, model: OpenaiApiChatModels = None, context_message_count: int = -1, extra_args: Optional[dict] = None, **_kwargs): @@ -75,7 +75,7 @@ async def ask(self, content: str, conversation_id: uuid.UUID = None, create_time=now_time, parent=parent_id, children=[], - content=OpenaiApiChatMessageTextContent(content_type="text", text=content), + content=OpenaiApiChatMessageTextContent(content_type="text", text=text_content), metadata=OpenaiApiChatMessageMetadata( source="openai_api", ) diff --git a/backend/api/sources/openai_web.py b/backend/api/sources/openai_web.py index 4ed912e2..7b15cd04 100644 --- a/backend/api/sources/openai_web.py +++ b/backend/api/sources/openai_web.py @@ -20,7 +20,8 @@ OpenaiWebChatMessageTetherBrowsingDisplayContent, OpenaiWebChatMessageTetherQuoteContent, \ OpenaiWebChatMessageContent, \ OpenaiWebChatMessageSystemErrorContent, OpenaiWebChatMessageStderrContent, \ - OpenaiWebChatMessageExecutionOutputContent, OpenaiWebChatMessageMultimodalTextContent + OpenaiWebChatMessageExecutionOutputContent, OpenaiWebChatMessageMultimodalTextContent, \ + OpenaiWebChatMessageMultimodalTextContentImagePart from api.models.json import UploadedFileOpenaiWebInfo from api.schemas.file_schemas import UploadedFileInfoSchema from api.schemas.openai_schemas import OpenaiChatPlugin, OpenaiChatPluginUserSettings, OpenaiChatFileUploadInfo, \ @@ -230,12 +231,13 @@ async def get_conversation_history(self, conversation_id: uuid.UUID | str) -> Op async def clear_conversations(self): # await self.chatbot.clear_conversations() url = f"{config.openai_web.chatgpt_base_url}conversations" - response = await self.session.patch(url, data={"is_visible": False}) + response = await self.session.patch(url, json={"is_visible": False}) await _check_response(response) - async def ask(self, content: str, conversation_id: uuid.UUID = None, parent_id: uuid.UUID = None, + async def ask(self, text_content: str, conversation_id: uuid.UUID = None, parent_id: uuid.UUID = None, model: OpenaiWebChatModels = None, plugin_ids: list[str] = None, - attachments: list[OpenaiWebAskAttachment] = None, **_kwargs): + attachments: list[OpenaiWebAskAttachment] = None, + multimodal_image_parts: list[OpenaiWebChatMessageMultimodalTextContentImagePart] = None, **_kwargs): assert config.openai_web.enabled, "OpenAI Web is not enabled" @@ -249,7 +251,7 @@ async def ask(self, content: str, conversation_id: uuid.UUID = None, parent_id: if plugin_ids is not None and model != OpenaiWebChatModels.gpt_4_plugins: raise InvalidParamsException("plugin_ids can only be set when model is gpt-4-plugins") - if content == ":continue": + if text_content == ":continue": data = { "action": "continue", "conversation_id": str(conversation_id) if conversation_id else None, @@ -259,9 +261,14 @@ async def ask(self, content: str, conversation_id: uuid.UUID = None, parent_id: "history_and_training_disabled": False, } else: - content = OpenaiWebChatMessageTextContent( - content_type="text", parts=[content] - ) + if not multimodal_image_parts: + content = OpenaiWebChatMessageTextContent( + content_type="text", parts=[text_content] + ) + else: + content = OpenaiWebChatMessageMultimodalTextContent( + content_type="multimodal_text", parts=multimodal_image_parts + [text_content] + ) messages = [ { @@ -320,21 +327,26 @@ async def ask(self, content: str, conversation_id: uuid.UUID = None, parent_id: async def delete_conversation(self, conversation_id: str): # await self.chatbot.delete_conversation(conversation_id) url = f"{config.openai_web.chatgpt_base_url}conversation/{conversation_id}" - response = await self.session.patch(url, data='{"is_visible": false}') + response = await self.session.patch(url, json={"is_visible": False}) await _check_response(response) async def set_conversation_title(self, conversation_id: str, title: str): url = f"{config.openai_web.chatgpt_base_url}conversation/{conversation_id}" - response = await self.session.patch(url, data=f'{{"title": "{title}"}}') + response = await self.session.patch(url, json={"title": title}) await _check_response(response) async def generate_conversation_title(self, conversation_id: str, message_id: str): url = f"{config.openai_web.chatgpt_base_url}conversation/gen_title/{conversation_id}" response = await self.session.post( url, - data=json.dumps({"message_id": message_id, "model": "text-davinci-002-render"}), + json={"message_id": message_id}, ) await _check_response(response) + result = response.json() + if result.get("title"): + return result.get("title") + else: + raise OpenaiWebException(f"Failed to generate title: {result.get('message')}") async def get_plugin_manifests(self, statuses="approved", is_installed=None, offset=0, limit=250): if not config.openai_web.is_plus_account: @@ -459,7 +471,8 @@ async def upload_file_in_server(self, file_info: UploadedFileInfoSchema) -> Uplo upload_url = upload_response.upload_url # 预签名的 azure 地址 # 上传文件 - content_type = file_info.content_type or guess_type(file_info.original_filename)[0] or "application/octet-stream" + content_type = file_info.content_type or guess_type(file_info.original_filename)[ + 0] or "application/octet-stream" headers = { 'x-ms-blob-type': 'BlockBlob', 'Content-Type': content_type, diff --git a/backend/pyproject.toml b/backend/pyproject.toml index aa524e38..92cf8ea3 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "chatgpt-share-backend" -version = "0.4.0-alpha6.1" +version = "0.4.0-alpha6" description = "" authors = ["moeakwak "] readme = "README.md" diff --git a/frontend/package.json b/frontend/package.json index 07eb1010..8c06162e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "chatgpt-share-frontend", "private": true, - "version": "0.4.0-alpha6.1", + "version": "0.4.0-alpha6.3", "type": "module", "scripts": { "dev": "vite --config ./config/vite.config.dev.ts", diff --git a/frontend/src/api/conv.ts b/frontend/src/api/conv.ts index 9a2b930a..8659265d 100644 --- a/frontend/src/api/conv.ts +++ b/frontend/src/api/conv.ts @@ -41,7 +41,7 @@ export function setConversationTitleApi(conversation_id: string, title: string) } export function generateConversationTitleApi(conversation_id: string, message_id: string) { - return axios.patch(ApiUrl.Conversation + '/' + conversation_id + '/gen_title', null, { + return axios.patch(ApiUrl.Conversation + '/' + conversation_id + '/gen_title', null, { params: { message_id }, }); } @@ -51,7 +51,7 @@ export function assignConversationToUserApi(conversation_id: string, username: s } export function getFileDownloadUrlApi(file_id: string) { - return axios.get(`${ApiUrl.Conversation}/files/${file_id}/download-url`); + return axios.get(`/files/${file_id}/download-url`); } export function getInterpreterInfoApi(conversation_id: string) { diff --git a/frontend/src/api/interceptor.ts b/frontend/src/api/interceptor.ts index d73432fe..936758e8 100644 --- a/frontend/src/api/interceptor.ts +++ b/frontend/src/api/interceptor.ts @@ -52,9 +52,7 @@ axios.interceptors.response.use( if (res.result) { msg += `: ${t(res.result)}`; } - Message.error(msg, { - duration: 5 * 1000, - }); + Message.error(msg, { duration: 3 * 1000 }); if ( [10401].includes(res.code) && !([ApiUrl.Login, ApiUrl.Logout] as Array).includes(response.config.url || '') diff --git a/frontend/src/components/ChatGPTAvatar.vue b/frontend/src/components/ChatGPTAvatar.vue index 5ea11d85..0c5d219e 100644 --- a/frontend/src/components/ChatGPTAvatar.vue +++ b/frontend/src/components/ChatGPTAvatar.vue @@ -46,6 +46,24 @@ + + + + + + + + + + + @@ -58,7 +76,7 @@ import ChatGPTIcon from './ChatGPTIcon.vue'; const props = defineProps<{ model?: string; - iconStyle?: 'default' | 'plugins' | 'browsing'; + iconStyle?: 'default' | 'plugins' | 'browsing' | 'code-interpreter'; color?: string; size?: any; }>(); diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 3d28267a..440c64c4 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -171,7 +171,10 @@ "expand": "expand", "export": "export", "import": "import", - "useCodeInterpreter": "Using Code Interpreter" + "useCodeInterpreter": "Using Code Interpreter", + "emptyFileList": "File list is empty", + "selectFile": "Select file(s)", + "viewAttachments": "Expand {0} attachments" }, "errors": { "403": "403 error: access denied", @@ -208,11 +211,13 @@ "openai": { "401": "OpenAI authorization failed (401 error), please contact the administrator", "403": "OpenAI authorization failed (403 error), please contact the administrator", - "404": "The OpenAI interface does not exist (404 error), please contact the administrator", - "429": "The OpenAI interface request is too frequent (429 error), it may be that the model usage limit has been exceeded, please try again later", + "404": "OpenAI reports a 404 error, please contact the administrator", + "429": "OpenAI reports a 429 error, it may be that the model usage limit has been exceeded, please try again later", + "500": "OpenAI server error (500 error), it may be that the OpenAI service fails or the model API has changed, please inform the administrator", "unkown": "OpenAI unknown error, please contact the administrator" }, - "unknown": "unknown mistake" + "unknown": "unknown error", + "invalidRequest": "Invalid Request" }, "tips": { "loginExpired": "Login expired. Do you want to go to the login page?", @@ -271,9 +276,18 @@ "NewConversationForm": { "failedToGetPlugins": "Failed to get list of plugins", "loadingPlugins": "Loading plugins...", - "selectPlugins": "select plugin" + "selectPlugins": "select plugin", + "leaveBlankToGenerateTitle": "Leave blank to automatically generate" }, - "openaiWebPluginsLengthMoreThan3": "The number of plugins cannot exceed 3" + "openaiWebPluginsLengthMoreThan3": "The number of plugins cannot exceed 3", + "dragFileHere": "Click or drag file(s) here to upload", + "dragImageHere": "Drag image(s) here to upload", + "fileUploadRequirements": "Please do not upload files containing sensitive information; file size shouldn't be excessively large", + "fileUploadSuccess": "File {0} uploaded successfully", + "fileUploadFailed": "File {0} upload failed", + "imageUploadRequirements": "Up to 4 pictures can be uploaded", + "sandboxFileDownloadError": "File download error", + "sandboxFileNotFound": "File {0} not found, either because the sandbox path is wrong or because the interpreter is expired." }, "labels": { "nickname": "Nickname", @@ -350,5 +364,13 @@ "enabled_models": "Set which models are enabled globally. Models that are not enabled here will not be available for all accounts.", "file_upload_strategy": "Determined how to upload files when using the code interpreter model. See the documentation for details" } + }, + "dialog": { + "content": { + "syncConversations": "Are you sure you want to sync all conversations manually? \nThis will fetch all conversations info from the OpenAI account and mark deleted conversations as invalid." + }, + "title": { + "syncConversations": "Sync conversations" + } } } diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index 0c1cb61d..8c13dce1 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -213,9 +213,11 @@ "403": "OpenAI 授权失败 (403 错误),请联系管理员处理", "404": "OpenAI 接口不存在 (404 错误),请联系管理员处理", "429": "OpenAI 接口请求过于频繁 (429 错误),可能是超过模型使用限制,请稍后再试", + "500": "OpenAI 服务器错误 (500 错误),可能是 OpenAI 服务故障或者模型接口发生变更,请告知管理员", "unkown": "OpenAI 未知错误,请联系管理员处理" }, - "unknown": "未知错误" + "unknown": "未知错误", + "invalidRequest": "非法请求" }, "tips": { "loginExpired": "登录已过期。是否跳转到登录页面?", @@ -274,7 +276,8 @@ "NewConversationForm": { "loadingPlugins": "加载插件中……", "selectPlugins": "选择插件", - "failedToGetPlugins": "获取插件列表失败" + "failedToGetPlugins": "获取插件列表失败", + "leaveBlankToGenerateTitle": "留空则自动生成" }, "openaiWebPluginsLengthMoreThan3": "插件数量不能超过3", "sandboxFileNotFound": "未找到文件 {0},这可能是因为路径错误,或者是因为解释器已经过期。", @@ -282,7 +285,9 @@ "dragFileHere": "点击或拖拽文件到此处以上传文件", "fileUploadRequirements": "请不要上传含有敏感信息的文件;文件大小不应过大", "fileUploadSuccess": "文件 {0} 上传成功", - "fileUploadFailed": "文件 {0} 上传失败" + "fileUploadFailed": "文件 {0} 上传失败", + "dragImageHere": "拖拽图片到此处以上传", + "imageUploadRequirements": "最多能够上传4张图片" }, "labels": { "nickname": "昵称", @@ -341,7 +346,7 @@ "gpt_4_browsing": "GPT-4 Browsing", "gpt_4_plugins": "GPT-4 Plugins", "gpt_4_mobile": "GPT-4 Mobile", - "gpt_4_code_interpreter": "GPT-4 代码解释器" + "gpt_4_code_interpreter": "GPT-4 代码执行器" }, "sources": { "openai_web": "OpenAI Web", diff --git a/frontend/src/store/index.ts b/frontend/src/store/index.ts index 1d77bba2..7337d957 100644 --- a/frontend/src/store/index.ts +++ b/frontend/src/store/index.ts @@ -2,10 +2,11 @@ import { createPinia } from 'pinia'; import useAppStore from './modules/app'; import useConversationStore from './modules/conversation'; +import useFileStore from './modules/file'; import useUserStore from './modules/user'; const pinia = createPinia(); -export { useAppStore, useConversationStore, useUserStore }; +export { useAppStore, useConversationStore, useFileStore, useUserStore }; export default pinia; diff --git a/frontend/src/store/modules/app.ts b/frontend/src/store/modules/app.ts index 5a620e60..7608f5ea 100644 --- a/frontend/src/store/modules/app.ts +++ b/frontend/src/store/modules/app.ts @@ -18,6 +18,8 @@ const useAppStore = defineStore('app', { codeAutoWrap: false, widerConversationPage: true, }), + lastSelectedSource: useStorage('lastSelectedSource', null), + lastSelectedModel: useStorage('lastSelectedModel', null), }), getters: {}, actions: { diff --git a/frontend/src/store/modules/conversation.ts b/frontend/src/store/modules/conversation.ts index eacc7d9f..7166132f 100644 --- a/frontend/src/store/modules/conversation.ts +++ b/frontend/src/store/modules/conversation.ts @@ -18,7 +18,7 @@ const useConversationStore = defineStore('conversation', { state: (): ConversationState => ({ conversations: [], conversationHistoryMap: {}, - newConversation: null, + newConversation: null }), getters: {}, actions: { @@ -57,12 +57,12 @@ const useConversationStore = defineStore('conversation', { createNewConversation(info: NewConversationInfo) { if ( - !info.title || !info.source || !info.model || !(info.source === 'openai_api' || info.source === 'openai_web') || - (info.model !== 'gpt_4_plugins' && info.openaiWebPlugins) + (info.model !== 'gpt_4_plugins' && info.openaiWebPlugins && info.openaiWebPlugins.length > 0) ) { + console.error('Invalid conversation info', info); throw new Error('Invalid conversation info'); } console.log(info); @@ -70,7 +70,7 @@ const useConversationStore = defineStore('conversation', { this.newConversation = { source: info.source, conversation_id: newConversationId, - title: info.title, + title: info.title || '', current_model: info.model, create_time: currentTime, update_time: currentTime, @@ -78,7 +78,7 @@ const useConversationStore = defineStore('conversation', { this.conversationHistoryMap[newConversationId] = { _id: newConversationId, source: info.source, - title: info.title, + title: info.title || '', current_model: info.model, create_time: currentTime, update_time: currentTime, diff --git a/frontend/src/store/modules/file.ts b/frontend/src/store/modules/file.ts new file mode 100644 index 00000000..00773556 --- /dev/null +++ b/frontend/src/store/modules/file.ts @@ -0,0 +1,37 @@ +import { defineStore } from 'pinia'; + +import { FileState } from '../types'; + +const useFileStore = defineStore('file', { + state: (): FileState => ({ + attachments: { + uploadedFileInfos: [], + naiveUiUploadFileInfos: [], + naiveUiFileIdToServerFileIdMap: {}, + }, + images: { + uploadedFileInfos: [], + naiveUiUploadFileInfos: [], + naiveUiFileIdToServerFileIdMap: {}, + imageMetadataMap: {}, + }, + }), + actions: { + clearAll() { + this.clearAttachments(); + this.clearImages(); + }, + clearAttachments() { + this.attachments.uploadedFileInfos = []; + this.attachments.naiveUiUploadFileInfos = []; + this.attachments.naiveUiFileIdToServerFileIdMap = {}; + }, + clearImages() { + this.images.uploadedFileInfos = []; + this.images.naiveUiUploadFileInfos = []; + this.attachments.naiveUiFileIdToServerFileIdMap = {}; + } + }, +}); + +export default useFileStore; diff --git a/frontend/src/store/types.ts b/frontend/src/store/types.ts index ec7121ac..9fea6e32 100644 --- a/frontend/src/store/types.ts +++ b/frontend/src/store/types.ts @@ -1,6 +1,7 @@ import { RemovableRef } from '@vueuse/core'; +import { UploadFileInfo } from 'naive-ui'; -import { BaseConversationHistory, BaseConversationSchema, UserRead } from '@/types/schema'; +import { BaseConversationHistory, BaseConversationSchema, UploadedFileInfoSchema, UserRead } from '@/types/schema'; interface UserState { user: UserRead | null; @@ -19,6 +20,8 @@ interface AppState { theme: any; language: RemovableRef<'zh-CN' | 'en-US' | string>; preference: RemovableRef; + lastSelectedSource: RemovableRef; + lastSelectedModel: RemovableRef; } interface ConversationState { @@ -27,4 +30,19 @@ interface ConversationState { conversationHistoryMap: Record; } -export type { AppState, ConversationState, UserState }; +type FileUploadGroup = { + uploadedFileInfos: UploadedFileInfoSchema[]; + naiveUiUploadFileInfos: UploadFileInfo[]; + naiveUiFileIdToServerFileIdMap: Record; +} + +type ImageUploadGroup = FileUploadGroup & { + imageMetadataMap: Record; // 使用 server 端的文件 id 作为 key +} + +interface FileState { + attachments: FileUploadGroup; + images: ImageUploadGroup; +} + +export type { AppState, ConversationState, FileState, UserState }; diff --git a/frontend/src/types/json/config_schema.json b/frontend/src/types/json/config_schema.json index eca41fda..e57b012e 100644 --- a/frontend/src/types/json/config_schema.json +++ b/frontend/src/types/json/config_schema.json @@ -9,7 +9,7 @@ "is_plus_account": true, "chatgpt_base_url": null, "proxy": null, - "common_timeout": 10, + "common_timeout": 20, "ask_timeout": 600, "sync_conversations_on_startup": true, "sync_conversations_schedule": false, @@ -30,7 +30,9 @@ "gpt_4_plugins": "gpt-4-plugins", "gpt_4_code_interpreter": "gpt-4-code-interpreter" }, - "file_upload_strategy": "browser_upload_only" + "file_upload_strategy": "browser_upload_only", + "enable_uploading_attachments": true, + "enable_uploading_multimodal_images": true }, "allOf": [ { @@ -99,6 +101,7 @@ "data_dir": "./data", "database_url": "sqlite+aiosqlite:///data/database.db", "mongodb_url": "mongodb://cws:password@mongo:27017", + "mongodb_db_name": "cws", "run_migration": false, "max_file_upload_size": 104857600 }, @@ -199,7 +202,7 @@ }, "common_timeout": { "title": "Common Timeout", - "default": 10, + "default": 20, "minimum": 1, "type": "integer" }, @@ -261,6 +264,16 @@ "$ref": "#/definitions/OpenaiWebFileUploadStrategyOption" } ] + }, + "enable_uploading_attachments": { + "title": "Enable Uploading Attachments", + "default": true, + "type": "boolean" + }, + "enable_uploading_multimodal_images": { + "title": "Enable Uploading Multimodal Images", + "default": true, + "type": "boolean" } } }, @@ -402,6 +415,11 @@ "default": "mongodb://cws:password@mongo:27017", "type": "string" }, + "mongodb_db_name": { + "title": "Mongodb Db Name", + "default": "cws", + "type": "string" + }, "run_migration": { "title": "Run Migration", "default": false, diff --git a/frontend/src/types/json/openapi.json b/frontend/src/types/json/openapi.json index 46314e12..7c4b0623 100644 --- a/frontend/src/types/json/openapi.json +++ b/frontend/src/types/json/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/auth/login":{"post":{"summary":"Auth:Jwt.Login","operationId":"auth_jwt_login_auth_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_auth_jwt_login_auth_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/logout":{"post":{"summary":"Auth:Jwt.Logout","operationId":"auth_jwt_logout_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/auth/register":{"post":{"tags":["auth"],"summary":"Register","description":"注册时不能指定setting,使用默认setting","operationId":"register_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user":{"get":{"tags":["user"],"summary":"Get All Users","operationId":"get_all_users_user_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user/me":{"get":{"tags":["user"],"summary":"Get Me","operationId":"get_me_user_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"patch":{"tags":["user"],"summary":"Update Me","operationId":"update_me_user_me_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user/{user_id}":{"get":{"tags":["user"],"summary":"Admin Get User","operationId":"admin_get_user_user__user_id__get","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"delete":{"tags":["user"],"summary":"Admin Delete User","operationId":"admin_delete_user_user__user_id__delete","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"patch":{"tags":["user"],"summary":"Admin Update User","operationId":"admin_update_user_user__user_id__patch","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdateAdmin"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user/{user_id}/setting":{"patch":{"tags":["user"],"summary":"Admin Update User Setting","operationId":"admin_update_user_setting_user__user_id__setting_patch","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSettingSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv":{"get":{"tags":["conversation"],"summary":"Get My Conversations","description":"返回自己的有效会话","operationId":"get_my_conversations_conv_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"delete":{"tags":["conversation"],"summary":"Delete All Conversation","operationId":"delete_all_conversation_conv_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/all":{"get":{"tags":["conversation"],"summary":"Get All Conversations","operationId":"get_all_conversations_conv_all_get","parameters":[{"required":false,"schema":{"type":"boolean","title":"Valid Only","default":false},"name":"valid_only","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}":{"get":{"tags":["conversation"],"summary":"Get Conversation History","operationId":"get_conversation_history_conv__conversation_id__get","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"delete":{"tags":["conversation"],"summary":"Delete Conversation","description":"软删除:标记为 invalid 并且从 chatgpt 账号中删除会话,但不会删除 mongodb 中的历史记录","operationId":"delete_conversation_conv__conversation_id__delete","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"patch":{"tags":["conversation"],"summary":"Update Conversation Title","operationId":"update_conversation_title_conv__conversation_id__patch","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"},{"required":true,"schema":{"type":"string","title":"Title"},"name":"title","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/cache":{"get":{"tags":["conversation"],"summary":"Get Conversation History From Cache","operationId":"get_conversation_history_from_cache_conv__conversation_id__cache_get","parameters":[{"required":true,"schema":{"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/vanish":{"delete":{"tags":["conversation"],"summary":"Vanish Conversation","description":"硬删除:删除数据库和账号中的对话和历史记录","operationId":"vanish_conversation_conv__conversation_id__vanish_delete","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/assign/{username}":{"patch":{"tags":["conversation"],"summary":"Assign Conversation","operationId":"assign_conversation_conv__conversation_id__assign__username__patch","parameters":[{"required":true,"schema":{"type":"string","title":"Username"},"name":"username","in":"path"},{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/gen_title":{"patch":{"tags":["conversation"],"summary":"Generate Conversation Title","operationId":"generate_conversation_title_conv__conversation_id__gen_title_patch","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"},{"required":true,"schema":{"type":"string","title":"Message Id"},"name":"message_id","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/interpreter":{"get":{"tags":["conversation"],"summary":"Get Conversation Interpreter Info","operationId":"get_conversation_interpreter_info_conv__conversation_id__interpreter_get","parameters":[{"required":true,"schema":{"type":"string","title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conv/files/{file_id}/download-url":{"get":{"tags":["conversation"],"summary":"Get File Download Url","operationId":"get_file_download_url_conv_files__file_id__download_url_get","parameters":[{"required":true,"schema":{"type":"string","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conv/{conversation_id}/interpreter/download-url":{"get":{"tags":["conversation"],"summary":"Get Conversation Interpreter Download Url","operationId":"get_conversation_interpreter_download_url_conv__conversation_id__interpreter_download_url_get","parameters":[{"required":true,"schema":{"type":"string","title":"Conversation Id"},"name":"conversation_id","in":"path"},{"required":true,"schema":{"type":"string","title":"Message Id"},"name":"message_id","in":"query"},{"required":true,"schema":{"type":"string","title":"Sandbox Path"},"name":"sandbox_path","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/openai-plugins/all":{"get":{"tags":["chat"],"summary":"Get All Openai Web Chat Plugins","operationId":"get_all_openai_web_chat_plugins_chat_openai_plugins_all_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/openai-plugins/installed":{"get":{"tags":["chat"],"summary":"Get Installed Openai Web Chat Plugins","operationId":"get_installed_openai_web_chat_plugins_chat_openai_plugins_installed_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/openai-plugin/{plugin_id}":{"get":{"tags":["chat"],"summary":"Get Openai Web Plugin","operationId":"get_openai_web_plugin_chat_openai_plugin__plugin_id__get","parameters":[{"required":true,"schema":{"type":"string","title":"Plugin Id"},"name":"plugin_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/openai-plugin/{plugin_id}/user-settings":{"patch":{"tags":["chat"],"summary":"Update Chat Plugin User Settings","operationId":"update_chat_plugin_user_settings_chat_openai_plugin__plugin_id__user_settings_patch","parameters":[{"required":true,"schema":{"type":"string","title":"Plugin Id"},"name":"plugin_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenaiChatPluginUserSettings"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/__schema_types":{"get":{"tags":["chat"],"summary":" Predict Schema Types","description":"只用来让 openapi 自动生成 schema,并不实际调用","operationId":"_predict_schema_types_chat___schema_types_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/system/info":{"get":{"tags":["system"],"summary":"Get System Info","operationId":"get_system_info_system_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/stats/request":{"get":{"tags":["system"],"summary":"Get Request Statistics","operationId":"get_request_statistics_system_stats_request_get","parameters":[{"required":false,"schema":{"type":"integer","title":"Granularity","default":1800},"name":"granularity","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/stats/ask":{"get":{"tags":["system"],"summary":"Get Ask Statistics","operationId":"get_ask_statistics_system_stats_ask_get","parameters":[{"required":false,"schema":{"type":"integer","title":"Granularity","default":1800},"name":"granularity","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/logs/server":{"post":{"tags":["system"],"summary":"Get Server Logs","operationId":"get_server_logs_system_logs_server_post","requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/LogFilterOptions"}],"title":"Options","default":{"max_lines":100}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/config":{"get":{"tags":["system"],"summary":"Get Config","operationId":"get_config_system_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"put":{"tags":["system"],"summary":"Update Config","operationId":"update_config_system_config_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigModel"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/credentials":{"get":{"tags":["system"],"summary":"Get Credentials","operationId":"get_credentials_system_credentials_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"put":{"tags":["system"],"summary":"Update Credentials","operationId":"update_credentials_system_credentials_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialsModel"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/action/sync-openai-web-conv":{"post":{"tags":["system"],"summary":"Sync Openai Web Conversations","operationId":"sync_openai_web_conversations_system_action_sync_openai_web_conv_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/status/common":{"get":{"tags":["status"],"summary":"Get Server Status","description":"普通用户获取服务器状态","operationId":"get_server_status_status_common_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/local/upload":{"post":{"tags":["files"],"summary":"Upload File To Local","description":"上传文件到服务器。文件将被保存在服务器上,返回文件信息。\n仅当需要在服务器留存上传的文件时才使用.","operationId":"upload_file_to_local_files_local_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_to_local_files_local_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/local/download/{file_id}":{"get":{"tags":["files"],"summary":"Download File From Local","operationId":"download_file_from_local_files_local_download__file_id__get","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/openai-web/upload-start":{"post":{"tags":["files"],"summary":"Start Upload To Openai","description":"要上传文件到 OpenAI Web,前端需要先调用此接口.\n1. 若最终上传方法是前端直接上传 (Browser -> Azure Blob),则获取上传地址并记录文件信息,响应中 upload_file_info 不为空\n2. 否则的话就是服务端中转上传(Browser -> Local -> Azure Blob,此时响应中 upload_file_info 为空,前端应当:\n a. 先调用 upload_file_to_local 接口上传文件到服务器,拿到文件的 uuid\n b. 再调用 upload_local_file_to_openai_web 接口,通知服务器上传文件到 OpenAI Web","operationId":"start_upload_to_openai_files_openai_web_upload_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenaiChatFileUploadInfo"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/openai-web/upload-complete/{file_id}":{"post":{"tags":["files"],"summary":"Complete Upload To Openai","operationId":"complete_upload_to_openai_files_openai_web_upload_complete__file_id__post","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/local/upload-to-openai-web/{file_id}":{"post":{"tags":["files"],"summary":"Upload Local File To Openai Web","description":"将服务器上已有的文件上传到 OpenAI Web(Azure blob)","operationId":"upload_local_file_to_openai_web_files_local_upload_to_openai_web__file_id__post","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}}},"components":{"schemas":{"AskLogAggregation":{"properties":{"_id":{"$ref":"#/components/schemas/AskLogAggregationID"},"count":{"type":"integer","title":"Count"},"user_ids":{"items":{"type":"integer"},"type":"array","title":"User Ids"},"total_queueing_time":{"type":"number","title":"Total Queueing Time"},"total_ask_time":{"type":"number","title":"Total Ask Time"}},"type":"object","required":["count"],"title":"AskLogAggregation"},"AskLogAggregationID":{"properties":{"start_time":{"type":"string","format":"date-time","title":"Start Time"},"meta":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebAskLogMeta"},{"$ref":"#/components/schemas/OpenaiApiAskLogMeta"}],"title":"Meta"}},"type":"object","required":["start_time"],"title":"AskLogAggregationID"},"AskRequest":{"properties":{"source":{"$ref":"#/components/schemas/ChatSourceTypes"},"model":{"type":"string","title":"Model"},"new_conversation":{"type":"boolean","title":"New Conversation"},"new_title":{"type":"string","title":"New Title"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"parent":{"type":"string","format":"uuid","title":"Parent"},"api_context_message_count":{"type":"integer","minimum":-1.0,"title":"Api Context Message Count","default":-1},"content":{"type":"string","title":"Content"},"openai_web_plugin_ids":{"items":{"type":"string"},"type":"array","title":"Openai Web Plugin Ids"},"openai_web_attachments":{"items":{"$ref":"#/components/schemas/OpenaiWebAskAttachment"},"type":"array","title":"Openai Web Attachments"}},"type":"object","required":["source","model","new_conversation","content"],"title":"AskRequest"},"AskResponse":{"properties":{"type":{"$ref":"#/components/schemas/AskResponseType"},"tip":{"type":"string","title":"Tip"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"message":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessage"},{"$ref":"#/components/schemas/OpenaiApiChatMessage"}],"title":"Message"},"error_detail":{"type":"string","title":"Error Detail"}},"type":"object","required":["type"],"title":"AskResponse"},"AskResponseType":{"type":"string","enum":["waiting","queueing","message","error"],"title":"AskResponseType","description":"An enumeration."},"AuthSetting":{"properties":{"jwt_secret":{"type":"string","title":"Jwt Secret","default":"MODIFY_THIS_TO_RANDOM_SECURE_STRING"},"jwt_lifetime_seconds":{"type":"integer","minimum":1.0,"title":"Jwt Lifetime Seconds","default":259200},"cookie_max_age":{"type":"integer","minimum":1.0,"title":"Cookie Max Age","default":259200},"user_secret":{"type":"string","title":"User Secret","default":"MODIFY_THIS_TO_ANOTHER_RANDOM_SECURE_STRING"}},"type":"object","title":"AuthSetting"},"BaseChatMessage":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"source":{"type":"string","enum":["openai_web","openai_api"],"title":"Source"},"role":{"anyOf":[{"type":"string","enum":["system","user","assistant","tool"]},{"type":"string"}],"title":"Role"},"author_name":{"anyOf":[{"type":"string","enum":["browser","python"]},{"type":"string"}],"title":"Author Name"},"model":{"type":"string","title":"Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"parent":{"type":"string","format":"uuid","title":"Parent"},"children":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Children"},"content":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageTextContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageCodeContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageExecutionOutputContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageStderrContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherBrowsingDisplayContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherQuoteContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageSystemErrorContent"}]},{"$ref":"#/components/schemas/OpenaiApiChatMessageTextContent"},{"type":"string"}],"title":"Content"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadata"},{"$ref":"#/components/schemas/OpenaiApiChatMessageMetadata"}],"title":"Metadata"}},"type":"object","required":["id","source","role","children"],"title":"BaseChatMessage"},"BaseConversationHistory":{"properties":{"_id":{"type":"string","format":"uuid","title":" Id"},"source":{"type":"string","enum":["openai_web","openai_api"],"title":"Source"},"title":{"type":"string","title":"Title"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"},"mapping":{"additionalProperties":{"$ref":"#/components/schemas/BaseChatMessage"},"type":"object","title":"Mapping"},"current_node":{"type":"string","format":"uuid","title":"Current Node"},"current_model":{"type":"string","title":"Current Model"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebConversationHistoryMeta"},{"$ref":"#/components/schemas/OpenaiApiConversationHistoryMeta"}],"title":"Metadata"}},"type":"object","required":["source","title","create_time","update_time","mapping"],"title":"BaseConversationHistory"},"BaseConversationSchema":{"properties":{"id":{"type":"integer","title":"Id","default":-1},"source":{"$ref":"#/components/schemas/ChatSourceTypes"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"integer","title":"User Id"},"is_valid":{"type":"boolean","title":"Is Valid","default":true},"current_model":{"type":"string","title":"Current Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"}},"type":"object","required":["source"],"title":"BaseConversationSchema"},"Body_auth_jwt_login_auth_login_post":{"properties":{"grant_type":{"type":"string","pattern":"password","title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"type":"string","title":"Client Id"},"client_secret":{"type":"string","title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_auth_jwt_login_auth_login_post"},"Body_upload_file_to_local_files_local_upload_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_file_to_local_files_local_upload_post"},"ChatSourceTypes":{"type":"string","enum":["openai_web","openai_api"],"title":"ChatSourceTypes","description":"An enumeration."},"CommonSetting":{"properties":{"print_sql":{"type":"boolean","title":"Print Sql","default":false},"create_initial_admin_user":{"type":"boolean","title":"Create Initial Admin User","default":true},"initial_admin_user_username":{"type":"string","title":"Initial Admin User Username","default":"admin"},"initial_admin_user_password":{"type":"string","title":"Initial Admin User Password","default":"password"}},"type":"object","title":"CommonSetting"},"CommonStatusSchema":{"properties":{"active_user_in_5m":{"type":"integer","title":"Active User In 5M"},"active_user_in_1h":{"type":"integer","title":"Active User In 1H"},"active_user_in_1d":{"type":"integer","title":"Active User In 1D"},"is_chatbot_busy":{"type":"boolean","title":"Is Chatbot Busy"},"chatbot_waiting_count":{"type":"integer","title":"Chatbot Waiting Count"},"gpt4_count_in_3_hours":{"type":"integer","title":"Gpt4 Count In 3 Hours"}},"type":"object","title":"CommonStatusSchema"},"ConfigModel":{"properties":{"openai_web":{"allOf":[{"$ref":"#/components/schemas/OpenaiWebChatGPTSetting"}],"title":"Openai Web","default":{"enabled":true,"is_plus_account":true,"common_timeout":10,"ask_timeout":600,"sync_conversations_on_startup":true,"sync_conversations_schedule":false,"sync_conversations_schedule_interval_hours":12,"enabled_models":["gpt_3_5","gpt_4","gpt_4_code_interpreter","gpt_4_plugins","gpt_4_browsing"],"model_code_mapping":{"gpt_3_5":"text-davinci-002-render-sha","gpt_3_5_mobile":"text-davinci-002-render-sha-mobile","gpt_4":"gpt-4","gpt_4_mobile":"gpt-4-mobile","gpt_4_browsing":"gpt-4-browsing","gpt_4_plugins":"gpt-4-plugins","gpt_4_code_interpreter":"gpt-4-code-interpreter"},"file_upload_strategy":"browser_upload_only"}},"openai_api":{"allOf":[{"$ref":"#/components/schemas/OpenaiApiSetting"}],"title":"Openai Api","default":{"enabled":true,"openai_base_url":"https://api.openai.com/v1/","connect_timeout":10,"read_timeout":20,"enabled_models":["gpt_3_5","gpt_4"],"model_code_mapping":{"gpt_3_5":"gpt-3.5-turbo","gpt_4":"gpt-4"}}},"common":{"allOf":[{"$ref":"#/components/schemas/CommonSetting"}],"title":"Common","default":{"print_sql":false,"create_initial_admin_user":true,"initial_admin_user_username":"admin","initial_admin_user_password":"password"}},"http":{"allOf":[{"$ref":"#/components/schemas/HttpSetting"}],"title":"Http","default":{"host":"127.0.0.1","port":8000,"cors_allow_origins":["http://localhost:8000","http://localhost:5173","http://127.0.0.1:8000","http://127.0.0.1:5173"]}},"data":{"allOf":[{"$ref":"#/components/schemas/DataSetting"}],"title":"Data","default":{"data_dir":"./data","database_url":"sqlite+aiosqlite:///data/database.db","mongodb_url":"mongodb://cws:password@mongo:27017","run_migration":false,"max_file_upload_size":104857600}},"auth":{"allOf":[{"$ref":"#/components/schemas/AuthSetting"}],"title":"Auth","default":{"jwt_secret":"MODIFY_THIS_TO_RANDOM_SECURE_STRING","jwt_lifetime_seconds":259200,"cookie_max_age":259200,"user_secret":"MODIFY_THIS_TO_ANOTHER_RANDOM_SECURE_STRING"}},"stats":{"allOf":[{"$ref":"#/components/schemas/StatsSetting"}],"title":"Stats","default":{"ask_stats_ttl":7776000,"request_stats_ttl":2592000,"request_stats_filter_keywords":["/status"]}},"log":{"allOf":[{"$ref":"#/components/schemas/LogSetting"}],"title":"Log","default":{"console_log_level":"INFO"}}},"type":"object","title":"ConfigModel"},"CredentialsModel":{"properties":{"openai_web_access_token":{"type":"string","title":"Openai Web Access Token"},"openai_api_key":{"type":"string","title":"Openai Api Key"}},"type":"object","title":"CredentialsModel"},"CustomOpenaiApiSettings":{"properties":{"url":{"type":"string","title":"Url"},"key":{"type":"string","title":"Key"}},"type":"object","title":"CustomOpenaiApiSettings"},"DailyTimeSlot":{"properties":{"start_time":{"type":"string","format":"time","title":"Start Time","description":"每天可使用的开始时间"},"end_time":{"type":"string","format":"time","title":"End Time","description":"每天可使用的结束时间"}},"type":"object","required":["start_time","end_time"],"title":"DailyTimeSlot"},"DataSetting":{"properties":{"data_dir":{"type":"string","title":"Data Dir","default":"./data"},"database_url":{"type":"string","title":"Database Url","default":"sqlite+aiosqlite:///data/database.db"},"mongodb_url":{"type":"string","title":"Mongodb Url","default":"mongodb://cws:password@mongo:27017"},"run_migration":{"type":"boolean","title":"Run Migration","default":false},"max_file_upload_size":{"type":"integer","minimum":0.0,"title":"Max File Upload Size","default":104857600}},"type":"object","title":"DataSetting"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HttpSetting":{"properties":{"host":{"type":"string","title":"Host","default":"127.0.0.1"},"port":{"type":"integer","maximum":65535.0,"minimum":1.0,"title":"Port","default":8000},"cors_allow_origins":{"items":{"type":"string"},"type":"array","title":"Cors Allow Origins","default":["http://localhost:8000","http://localhost:5173","http://127.0.0.1:8000","http://127.0.0.1:5173"]}},"type":"object","title":"HttpSetting"},"LogFilterOptions":{"properties":{"max_lines":{"type":"integer","title":"Max Lines","default":100},"exclude_keywords":{"items":{"type":"string"},"type":"array","title":"Exclude Keywords"}},"type":"object","title":"LogFilterOptions"},"LogSetting":{"properties":{"console_log_level":{"type":"string","enum":["INFO","DEBUG","WARNING"],"title":"Console Log Level","default":"INFO"}},"type":"object","title":"LogSetting"},"OpenaiApiAskLogMeta":{"properties":{"source":{"type":"string","enum":["openai_api"],"title":"Source"},"model":{"$ref":"#/components/schemas/OpenaiApiChatModels"}},"type":"object","required":["source","model"],"title":"OpenaiApiAskLogMeta"},"OpenaiApiChatMessage":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"source":{"type":"string","enum":["openai_api"],"title":"Source"},"role":{"anyOf":[{"type":"string","enum":["system","user","assistant","tool"]},{"type":"string"}],"title":"Role"},"author_name":{"anyOf":[{"type":"string","enum":["browser","python"]},{"type":"string"}],"title":"Author Name"},"model":{"type":"string","title":"Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"parent":{"type":"string","format":"uuid","title":"Parent"},"children":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Children"},"content":{"$ref":"#/components/schemas/OpenaiApiChatMessageTextContent"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadata"},{"$ref":"#/components/schemas/OpenaiApiChatMessageMetadata"}],"title":"Metadata"}},"type":"object","required":["id","source","role","children"],"title":"OpenaiApiChatMessage"},"OpenaiApiChatMessageMetadata":{"properties":{"source":{"type":"string","enum":["openai_api"],"title":"Source"},"usage":{"$ref":"#/components/schemas/OpenaiChatResponseUsage"},"finish_reason":{"type":"string","title":"Finish Reason"}},"type":"object","required":["source"],"title":"OpenaiApiChatMessageMetadata"},"OpenaiApiChatMessageTextContent":{"properties":{"content_type":{"type":"string","enum":["text"],"title":"Content Type"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type","text"],"title":"OpenaiApiChatMessageTextContent"},"OpenaiApiChatModels":{"type":"string","enum":["gpt_3_5","gpt_4"],"title":"OpenaiApiChatModels","description":"An enumeration."},"OpenaiApiConversationHistoryDocument":{"properties":{"_id":{"type":"string","format":"uuid","title":" Id"},"source":{"type":"string","enum":["openai_api"],"title":"Source"},"title":{"type":"string","title":"Title"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"},"mapping":{"additionalProperties":{"$ref":"#/components/schemas/OpenaiApiChatMessage"},"type":"object","title":"Mapping"},"current_node":{"type":"string","format":"uuid","title":"Current Node"},"current_model":{"type":"string","title":"Current Model"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebConversationHistoryMeta"},{"$ref":"#/components/schemas/OpenaiApiConversationHistoryMeta"}],"title":"Metadata"}},"type":"object","required":["source","title","create_time","update_time","mapping"],"title":"OpenaiApiConversationHistoryDocument","description":"Document Mapping class.\n\nFields:\n\n- `id` - MongoDB document ObjectID \"_id\" field.\nMapped to the PydanticObjectId class"},"OpenaiApiConversationHistoryMeta":{"properties":{"source":{"type":"string","enum":["openai_api"],"title":"Source"}},"type":"object","required":["source"],"title":"OpenaiApiConversationHistoryMeta"},"OpenaiApiConversationSchema":{"properties":{"id":{"type":"integer","title":"Id","default":-1},"source":{"type":"string","enum":["openai_api"],"title":"Source"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"integer","title":"User Id"},"is_valid":{"type":"boolean","title":"Is Valid","default":true},"current_model":{"type":"string","title":"Current Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"}},"type":"object","required":["source"],"title":"OpenaiApiConversationSchema"},"OpenaiApiPerModelAskCount":{"additionalProperties":{"type":"integer"},"type":"object","title":"OpenaiApiPerModelAskCount","default":{"gpt_3_5":0,"gpt_4":0}},"OpenaiApiSetting":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"openai_base_url":{"type":"string","title":"Openai Base Url","default":"https://api.openai.com/v1/"},"proxy":{"type":"string","title":"Proxy"},"connect_timeout":{"type":"integer","minimum":1.0,"title":"Connect Timeout","default":10},"read_timeout":{"type":"integer","minimum":1.0,"title":"Read Timeout","default":20},"enabled_models":{"items":{"$ref":"#/components/schemas/OpenaiApiChatModels"},"type":"array","default":["gpt_3_5","gpt_4"]},"model_code_mapping":{"additionalProperties":{"type":"string"},"type":"object","title":"Model Code Mapping","default":{"gpt_3_5":"gpt-3.5-turbo","gpt_4":"gpt-4"}}},"type":"object","title":"OpenaiApiSetting"},"OpenaiApiSourceSettingSchema":{"properties":{"allow_to_use":{"type":"boolean","title":"Allow To Use"},"valid_until":{"type":"string","format":"date-time","title":"Valid Until"},"max_conv_count":{"type":"integer","title":"Max Conv Count"},"total_ask_count":{"type":"integer","title":"Total Ask Count"},"rate_limits":{"items":{"$ref":"#/components/schemas/TimeWindowRateLimit"},"type":"array","title":"Rate Limits"},"daily_available_time_slots":{"items":{"$ref":"#/components/schemas/DailyTimeSlot"},"type":"array","title":"Daily Available Time Slots"},"available_models":{"items":{"$ref":"#/components/schemas/OpenaiApiChatModels"},"type":"array"},"per_model_ask_count":{"$ref":"#/components/schemas/OpenaiApiPerModelAskCount"},"allow_custom_openai_api":{"type":"boolean","title":"Allow Custom Openai Api"},"custom_openai_api_settings":{"$ref":"#/components/schemas/CustomOpenaiApiSettings"}},"type":"object","required":["allow_to_use","max_conv_count","total_ask_count","rate_limits","daily_available_time_slots","available_models","per_model_ask_count","allow_custom_openai_api","custom_openai_api_settings"],"title":"OpenaiApiSourceSettingSchema"},"OpenaiChatFileUploadInfo":{"properties":{"file_name":{"type":"string","title":"File Name"},"file_size":{"type":"integer","title":"File Size"},"use_case":{"anyOf":[{"type":"string"},{"type":"string","enum":["ace_upload"]}],"title":"Use Case"}},"type":"object","required":["file_name","file_size","use_case"],"title":"OpenaiChatFileUploadInfo"},"OpenaiChatInterpreterInfo":{"properties":{"kernel_started":{"type":"boolean","title":"Kernel Started"},"time_remaining_ms":{"type":"integer","title":"Time Remaining Ms"}},"type":"object","title":"OpenaiChatInterpreterInfo"},"OpenaiChatPlugin":{"properties":{"id":{"type":"string","title":"Id"},"namespace":{"type":"string","title":"Namespace"},"manifest":{"$ref":"#/components/schemas/OpenaiChatPluginManifest"},"categories":{"items":{"$ref":"#/components/schemas/OpenaiChatPluginCategory"},"type":"array","title":"Categories"},"domain":{"type":"string","title":"Domain"},"status":{"anyOf":[{"type":"string","enum":["approved"]},{"type":"string"}],"title":"Status"},"user_settings":{"anyOf":[{"$ref":"#/components/schemas/OpenaiChatPluginUserSettings"},{"type":"object"}],"title":"User Settings"},"oauth_client_id":{"type":"string","title":"Oauth Client Id"}},"type":"object","title":"OpenaiChatPlugin"},"OpenaiChatPluginCategory":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","title":"Title"}},"type":"object","title":"OpenaiChatPluginCategory"},"OpenaiChatPluginManifest":{"properties":{"api":{"type":"object","title":"Api"},"auth":{"type":"object","title":"Auth"},"logo_url":{"type":"string","title":"Logo Url"},"contact_email":{"type":"string","title":"Contact Email"},"schema_version":{"type":"string","title":"Schema Version"},"name_for_model":{"type":"string","title":"Name For Model"},"name_for_human":{"type":"string","title":"Name For Human"},"description_for_model":{"type":"string","title":"Description For Model"},"description_for_human":{"type":"string","title":"Description For Human"},"legal_info_url":{"type":"string","title":"Legal Info Url"}},"type":"object","title":"OpenaiChatPluginManifest"},"OpenaiChatPluginUserSettings":{"properties":{"is_authenticated":{"type":"boolean","title":"Is Authenticated"},"is_installed":{"type":"boolean","title":"Is Installed"}},"type":"object","title":"OpenaiChatPluginUserSettings"},"OpenaiChatResponseUsage":{"properties":{"prompt_tokens":{"type":"integer","title":"Prompt Tokens"},"completion_tokens":{"type":"integer","title":"Completion Tokens"}},"type":"object","title":"OpenaiChatResponseUsage"},"OpenaiWebAskAttachment":{"properties":{"name":{"type":"string","title":"Name"},"id":{"type":"string","title":"Id"},"size":{"type":"integer","title":"Size"}},"type":"object","required":["name","id","size"],"title":"OpenaiWebAskAttachment"},"OpenaiWebAskLogMeta":{"properties":{"source":{"type":"string","enum":["openai_web"],"title":"Source"},"model":{"$ref":"#/components/schemas/OpenaiWebChatModels"}},"type":"object","required":["source","model"],"title":"OpenaiWebAskLogMeta"},"OpenaiWebChatGPTSetting":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"is_plus_account":{"type":"boolean","title":"Is Plus Account","default":true},"chatgpt_base_url":{"type":"string","title":"Chatgpt Base Url"},"proxy":{"type":"string","title":"Proxy"},"common_timeout":{"type":"integer","minimum":1.0,"title":"Common Timeout","default":10},"ask_timeout":{"type":"integer","minimum":1.0,"title":"Ask Timeout","default":600},"sync_conversations_on_startup":{"type":"boolean","title":"Sync Conversations On Startup","default":true},"sync_conversations_schedule":{"type":"boolean","title":"Sync Conversations Schedule","default":false},"sync_conversations_schedule_interval_hours":{"type":"integer","minimum":1.0,"title":"Sync Conversations Schedule Interval Hours","default":12},"enabled_models":{"items":{"$ref":"#/components/schemas/OpenaiWebChatModels"},"type":"array","default":["gpt_3_5","gpt_4","gpt_4_code_interpreter","gpt_4_plugins","gpt_4_browsing"]},"model_code_mapping":{"additionalProperties":{"type":"string"},"type":"object","title":"Model Code Mapping","default":{"gpt_3_5":"text-davinci-002-render-sha","gpt_3_5_mobile":"text-davinci-002-render-sha-mobile","gpt_4":"gpt-4","gpt_4_mobile":"gpt-4-mobile","gpt_4_browsing":"gpt-4-browsing","gpt_4_plugins":"gpt-4-plugins","gpt_4_code_interpreter":"gpt-4-code-interpreter"}},"file_upload_strategy":{"allOf":[{"$ref":"#/components/schemas/OpenaiWebFileUploadStrategyOption"}],"default":"browser_upload_only"}},"type":"object","title":"OpenaiWebChatGPTSetting"},"OpenaiWebChatMessage":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"source":{"type":"string","enum":["openai_web"],"title":"Source"},"role":{"anyOf":[{"type":"string","enum":["system","user","assistant","tool"]},{"type":"string"}],"title":"Role"},"author_name":{"anyOf":[{"type":"string","enum":["browser","python"]},{"type":"string"}],"title":"Author Name"},"model":{"type":"string","title":"Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"parent":{"type":"string","format":"uuid","title":"Parent"},"children":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Children"},"content":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageTextContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageCodeContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageExecutionOutputContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageStderrContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherBrowsingDisplayContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherQuoteContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageSystemErrorContent"}],"title":"Content"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadata"},{"$ref":"#/components/schemas/OpenaiApiChatMessageMetadata"}],"title":"Metadata"}},"type":"object","required":["id","source","role","children"],"title":"OpenaiWebChatMessage"},"OpenaiWebChatMessageCodeContent":{"properties":{"content_type":{"type":"string","enum":["code"],"title":"Content Type"},"language":{"type":"string","title":"Language"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageCodeContent"},"OpenaiWebChatMessageExecutionOutputContent":{"properties":{"content_type":{"type":"string","enum":["execution_output"],"title":"Content Type"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageExecutionOutputContent"},"OpenaiWebChatMessageMetadata":{"properties":{"source":{"type":"string","enum":["openai_web"],"title":"Source"},"finish_details":{"type":"object","title":"Finish Details"},"weight":{"type":"number","title":"Weight"},"end_turn":{"type":"boolean","title":"End Turn"},"message_status":{"type":"string","title":"Message Status"},"recipient":{"anyOf":[{"type":"string","enum":["all","browser","python"]},{"type":"string"}],"title":"Recipient"},"fallback_content":{"title":"Fallback Content"},"invoked_plugin":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataPlugin"},"command":{"anyOf":[{"type":"string","enum":["search"]},{"type":"string"}],"title":"Command"},"args":{"items":{"type":"string"},"type":"array","title":"Args"},"status":{"anyOf":[{"type":"string","enum":["finished"]},{"type":"string"}],"title":"Status"},"_cite_metadata":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCite"},"citations":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCitation"},"type":"array","title":"Citations"},"attachments":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataAttachment"},"type":"array","title":"Attachments"},"is_complete":{"type":"boolean","title":"Is Complete"},"aggregate_result":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataAggregateResult"}},"type":"object","required":["source"],"title":"OpenaiWebChatMessageMetadata"},"OpenaiWebChatMessageMetadataAggregateResult":{"properties":{"status":{"anyOf":[{"type":"string","enum":["failed_with_in_kernel_exception","success"]},{"type":"string"}],"title":"Status"},"run_id":{"type":"string","title":"Run Id"},"start_time":{"type":"number","title":"Start Time"},"update_time":{"type":"number","title":"Update Time"},"end_time":{"type":"number","title":"End Time"},"final_expression_output":{"title":"Final Expression Output"},"code":{"type":"string","title":"Code"},"in_kernel_exception":{"type":"object","title":"In Kernel Exception"},"messages":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataAggregateResultMessage"},"type":"array","title":"Messages"},"jupyter_messages":{"items":{},"type":"array","title":"Jupyter Messages"}},"type":"object","title":"OpenaiWebChatMessageMetadataAggregateResult"},"OpenaiWebChatMessageMetadataAggregateResultMessage":{"properties":{"message_type":{"anyOf":[{"type":"string","enum":["image","stream"]},{"type":"string"}],"title":"Message Type"},"time":{"type":"number","title":"Time"},"sender":{"anyOf":[{"type":"string","enum":["server"]},{"type":"string"}],"title":"Sender"},"image_url":{"type":"string","title":"Image Url"},"stream_name":{"type":"string","title":"Stream Name"},"text":{"type":"string","title":"Text"}},"type":"object","title":"OpenaiWebChatMessageMetadataAggregateResultMessage"},"OpenaiWebChatMessageMetadataAttachment":{"properties":{"name":{"type":"string","title":"Name"},"id":{"type":"string","title":"Id"},"size":{"type":"integer","title":"Size"}},"type":"object","title":"OpenaiWebChatMessageMetadataAttachment"},"OpenaiWebChatMessageMetadataCitation":{"properties":{"start_ix":{"type":"integer","title":"Start Ix"},"end_ix":{"type":"integer","title":"End Ix"},"metadata":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCiteData"}},"type":"object","title":"OpenaiWebChatMessageMetadataCitation"},"OpenaiWebChatMessageMetadataCite":{"properties":{"citation_format":{"type":"object","title":"Citation Format"},"metadata_list":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCiteData"},"type":"array","title":"Metadata List"}},"type":"object","title":"OpenaiWebChatMessageMetadataCite"},"OpenaiWebChatMessageMetadataCiteData":{"properties":{"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"},"text":{"type":"string","title":"Text"}},"type":"object","title":"OpenaiWebChatMessageMetadataCiteData"},"OpenaiWebChatMessageMetadataPlugin":{"properties":{"http_response_status":{"type":"integer","title":"Http Response Status"},"namespace":{"type":"string","title":"Namespace"},"plugin_id":{"type":"string","title":"Plugin Id"},"type":{"type":"string","title":"Type"}},"type":"object","title":"OpenaiWebChatMessageMetadataPlugin"},"OpenaiWebChatMessageStderrContent":{"properties":{"content_type":{"type":"string","enum":["stderr"],"title":"Content Type"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageStderrContent"},"OpenaiWebChatMessageSystemErrorContent":{"properties":{"content_type":{"type":"string","enum":["system_error"],"title":"Content Type"},"name":{"anyOf":[{"type":"string","enum":["tool_error"]},{"type":"string"}],"title":"Name"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageSystemErrorContent"},"OpenaiWebChatMessageTetherBrowsingDisplayContent":{"properties":{"content_type":{"type":"string","enum":["tether_browsing_display"],"title":"Content Type"},"result":{"type":"string","title":"Result"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageTetherBrowsingDisplayContent"},"OpenaiWebChatMessageTetherQuoteContent":{"properties":{"content_type":{"type":"string","enum":["tether_quote"],"title":"Content Type"},"url":{"type":"string","title":"Url"},"domain":{"type":"string","title":"Domain"},"text":{"type":"string","title":"Text"},"title":{"type":"string","title":"Title"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageTetherQuoteContent"},"OpenaiWebChatMessageTextContent":{"properties":{"content_type":{"type":"string","enum":["text"],"title":"Content Type"},"parts":{"items":{"type":"string"},"type":"array","title":"Parts"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageTextContent"},"OpenaiWebChatModels":{"type":"string","enum":["gpt_3_5","gpt_3_5_mobile","gpt_4","gpt_4_mobile","gpt_4_browsing","gpt_4_plugins","gpt_4_code_interpreter"],"title":"OpenaiWebChatModels","description":"An enumeration."},"OpenaiWebChatStatus":{"type":"string","enum":["asking","queueing","idling"],"title":"OpenaiWebChatStatus","description":"An enumeration."},"OpenaiWebConversationHistoryDocument":{"properties":{"_id":{"type":"string","format":"uuid","title":" Id"},"source":{"type":"string","enum":["openai_web"],"title":"Source"},"title":{"type":"string","title":"Title"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"},"mapping":{"additionalProperties":{"$ref":"#/components/schemas/OpenaiWebChatMessage"},"type":"object","title":"Mapping"},"current_node":{"type":"string","format":"uuid","title":"Current Node"},"current_model":{"type":"string","title":"Current Model"},"metadata":{"$ref":"#/components/schemas/OpenaiWebConversationHistoryMeta"}},"type":"object","required":["source","title","create_time","update_time","mapping"],"title":"OpenaiWebConversationHistoryDocument","description":"Document Mapping class.\n\nFields:\n\n- `id` - MongoDB document ObjectID \"_id\" field.\nMapped to the PydanticObjectId class"},"OpenaiWebConversationHistoryMeta":{"properties":{"source":{"type":"string","enum":["openai_web"],"title":"Source"},"moderation_results":{"items":{},"type":"array","title":"Moderation Results"},"plugin_ids":{"items":{"type":"string"},"type":"array","title":"Plugin Ids"}},"type":"object","required":["source"],"title":"OpenaiWebConversationHistoryMeta"},"OpenaiWebConversationSchema":{"properties":{"id":{"type":"integer","title":"Id","default":-1},"source":{"type":"string","enum":["openai_web"],"title":"Source"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"integer","title":"User Id"},"is_valid":{"type":"boolean","title":"Is Valid","default":true},"current_model":{"type":"string","title":"Current Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"}},"type":"object","required":["source"],"title":"OpenaiWebConversationSchema"},"OpenaiWebFileUploadStrategyOption":{"type":"string","enum":["disable_upload","server_upload_only","browser_upload_only","browser_upload_when_file_size_exceed"],"title":"OpenaiWebFileUploadStrategyOption","description":"An enumeration."},"OpenaiWebPerModelAskCount":{"additionalProperties":{"type":"integer"},"type":"object","title":"OpenaiWebPerModelAskCount","default":{"gpt_3_5":0,"gpt_3_5_mobile":0,"gpt_4":0,"gpt_4_mobile":0,"gpt_4_browsing":0,"gpt_4_plugins":0,"gpt_4_code_interpreter":0}},"OpenaiWebSourceSettingSchema":{"properties":{"allow_to_use":{"type":"boolean","title":"Allow To Use"},"valid_until":{"type":"string","format":"date-time","title":"Valid Until"},"max_conv_count":{"type":"integer","title":"Max Conv Count"},"total_ask_count":{"type":"integer","title":"Total Ask Count"},"rate_limits":{"items":{"$ref":"#/components/schemas/TimeWindowRateLimit"},"type":"array","title":"Rate Limits"},"daily_available_time_slots":{"items":{"$ref":"#/components/schemas/DailyTimeSlot"},"type":"array","title":"Daily Available Time Slots"},"available_models":{"items":{"$ref":"#/components/schemas/OpenaiWebChatModels"},"type":"array"},"per_model_ask_count":{"$ref":"#/components/schemas/OpenaiWebPerModelAskCount"}},"type":"object","required":["allow_to_use","max_conv_count","total_ask_count","rate_limits","daily_available_time_slots","available_models","per_model_ask_count"],"title":"OpenaiWebSourceSettingSchema"},"RequestLogAggregation":{"properties":{"_id":{"$ref":"#/components/schemas/RequestLogAggregationID"},"count":{"type":"integer","title":"Count"},"user_ids":{"items":{"type":"integer"},"type":"array","title":"User Ids"},"avg_elapsed_ms":{"type":"number","title":"Avg Elapsed Ms"}},"type":"object","required":["_id","count"],"title":"RequestLogAggregation"},"RequestLogAggregationID":{"properties":{"start_time":{"type":"string","format":"date-time","title":"Start Time"},"route_path":{"type":"string","title":"Route Path"},"method":{"type":"string","title":"Method"}},"type":"object","title":"RequestLogAggregationID"},"StartUploadResponseSchema":{"properties":{"strategy":{"$ref":"#/components/schemas/OpenaiWebFileUploadStrategyOption"},"file_max_size":{"type":"integer","title":"File Max Size"},"upload_file_info":{"$ref":"#/components/schemas/UploadedFileInfoSchema"}},"type":"object","required":["strategy","file_max_size"],"title":"StartUploadResponseSchema"},"StatsSetting":{"properties":{"ask_stats_ttl":{"type":"integer","title":"Ask Stats Ttl","default":7776000},"request_stats_ttl":{"type":"integer","title":"Request Stats Ttl","default":2592000},"request_stats_filter_keywords":{"items":{"type":"string"},"type":"array","title":"Request Stats Filter Keywords","default":["/status"]}},"type":"object","title":"StatsSetting"},"SystemInfo":{"properties":{"startup_time":{"type":"number","title":"Startup Time"},"total_user_count":{"type":"integer","title":"Total User Count"},"total_conversation_count":{"type":"integer","title":"Total Conversation Count"},"valid_conversation_count":{"type":"integer","title":"Valid Conversation Count"}},"type":"object","required":["startup_time","total_user_count","total_conversation_count","valid_conversation_count"],"title":"SystemInfo"},"TimeWindowRateLimit":{"properties":{"window_seconds":{"type":"integer","title":"Window Seconds","description":"时间窗口大小,单位为秒"},"max_requests":{"type":"integer","title":"Max Requests","description":"在给定时间窗口内最多的请求次数"}},"type":"object","required":["window_seconds","max_requests"],"title":"TimeWindowRateLimit"},"UploadedFileInfoSchema":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"original_filename":{"type":"string","title":"Original Filename"},"size":{"type":"integer","title":"Size"},"storage_path":{"type":"string","title":"Storage Path"},"content_type":{"type":"string","title":"Content Type"},"upload_time":{"type":"string","format":"date-time","title":"Upload Time"},"uploader_id":{"type":"integer","title":"Uploader Id"},"openai_web_info":{"$ref":"#/components/schemas/UploadedFileOpenaiWebInfo"}},"type":"object","required":["id","original_filename","size","upload_time","uploader_id"],"title":"UploadedFileInfoSchema"},"UploadedFileOpenaiWebInfo":{"properties":{"file_id":{"type":"string","title":"File Id"},"upload_url":{"type":"string","title":"Upload Url","description":"上传文件的url, 上传后应清空该字段"},"download_url":{"type":"string","title":"Download Url"}},"type":"object","title":"UploadedFileOpenaiWebInfo"},"UserCreate":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"},"is_active":{"type":"boolean","title":"Is Active","default":true},"is_superuser":{"type":"boolean","title":"Is Superuser","default":false},"is_verified":{"type":"boolean","title":"Is Verified","default":false},"username":{"type":"string","title":"Username"},"nickname":{"type":"string","title":"Nickname"},"avatar":{"type":"string","title":"Avatar"},"remark":{"type":"string","title":"Remark"}},"type":"object","required":["email","password","username","nickname"],"title":"UserCreate"},"UserRead":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"username":{"type":"string","title":"Username"},"nickname":{"type":"string","title":"Nickname"},"last_active_time":{"type":"string","format":"date-time","title":"Last Active Time"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"avatar":{"type":"string","title":"Avatar"},"setting":{"$ref":"#/components/schemas/UserSettingSchema"}},"type":"object","required":["id","email","is_active","is_superuser","is_verified","username","nickname","create_time","setting"],"title":"UserRead","description":"Base User model."},"UserReadAdmin":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"username":{"type":"string","title":"Username"},"nickname":{"type":"string","title":"Nickname"},"last_active_time":{"type":"string","format":"date-time","title":"Last Active Time"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"avatar":{"type":"string","title":"Avatar"},"setting":{"$ref":"#/components/schemas/UserSettingSchema"},"remark":{"type":"string","title":"Remark"}},"type":"object","required":["id","email","is_active","is_superuser","is_verified","username","nickname","create_time","setting"],"title":"UserReadAdmin","description":"Base User model."},"UserSettingSchema":{"properties":{"id":{"type":"integer","title":"Id"},"user_id":{"type":"integer","title":"User Id"},"credits":{"type":"number","title":"Credits"},"openai_web_chat_status":{"$ref":"#/components/schemas/OpenaiWebChatStatus"},"openai_web":{"$ref":"#/components/schemas/OpenaiWebSourceSettingSchema"},"openai_api":{"$ref":"#/components/schemas/OpenaiApiSourceSettingSchema"}},"type":"object","required":["credits","openai_web_chat_status","openai_web","openai_api"],"title":"UserSettingSchema"},"UserUpdate":{"properties":{"password":{"type":"string","title":"Password"},"email":{"type":"string","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"nickname":{"type":"string","title":"Nickname"},"avatar":{"type":"string","title":"Avatar"}},"type":"object","title":"UserUpdate"},"UserUpdateAdmin":{"properties":{"password":{"type":"string","title":"Password"},"email":{"type":"string","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"nickname":{"type":"string","title":"Nickname"},"avatar":{"type":"string","title":"Avatar"},"username":{"type":"string","title":"Username"},"remark":{"type":"string","title":"Remark"}},"type":"object","title":"UserUpdateAdmin"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"APIKeyCookie":{"type":"apiKey","in":"cookie","name":"cws_user_auth"}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/auth/login":{"post":{"summary":"Auth:Jwt.Login","operationId":"auth_jwt_login_auth_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_auth_jwt_login_auth_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/logout":{"post":{"summary":"Auth:Jwt.Logout","operationId":"auth_jwt_logout_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/auth/register":{"post":{"tags":["auth"],"summary":"Register","description":"注册时不能指定setting,使用默认setting","operationId":"register_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user":{"get":{"tags":["user"],"summary":"Get All Users","operationId":"get_all_users_user_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user/me":{"get":{"tags":["user"],"summary":"Get Me","operationId":"get_me_user_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"patch":{"tags":["user"],"summary":"Update Me","operationId":"update_me_user_me_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user/{user_id}":{"get":{"tags":["user"],"summary":"Admin Get User","operationId":"admin_get_user_user__user_id__get","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"delete":{"tags":["user"],"summary":"Admin Delete User","operationId":"admin_delete_user_user__user_id__delete","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"patch":{"tags":["user"],"summary":"Admin Update User","operationId":"admin_update_user_user__user_id__patch","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdateAdmin"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/user/{user_id}/setting":{"patch":{"tags":["user"],"summary":"Admin Update User Setting","operationId":"admin_update_user_setting_user__user_id__setting_patch","parameters":[{"required":true,"schema":{"type":"integer","title":"User Id"},"name":"user_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSettingSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv":{"get":{"tags":["conversation"],"summary":"Get My Conversations","description":"返回自己的有效会话","operationId":"get_my_conversations_conv_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"delete":{"tags":["conversation"],"summary":"Delete All Conversation","operationId":"delete_all_conversation_conv_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/all":{"get":{"tags":["conversation"],"summary":"Get All Conversations","operationId":"get_all_conversations_conv_all_get","parameters":[{"required":false,"schema":{"type":"boolean","title":"Valid Only","default":false},"name":"valid_only","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}":{"get":{"tags":["conversation"],"summary":"Get Conversation History","operationId":"get_conversation_history_conv__conversation_id__get","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"delete":{"tags":["conversation"],"summary":"Delete Conversation","description":"软删除:标记为 invalid 并且从 chatgpt 账号中删除会话,但不会删除 mongodb 中的历史记录","operationId":"delete_conversation_conv__conversation_id__delete","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]},"patch":{"tags":["conversation"],"summary":"Update Conversation Title","operationId":"update_conversation_title_conv__conversation_id__patch","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"},{"required":true,"schema":{"type":"string","title":"Title"},"name":"title","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/cache":{"get":{"tags":["conversation"],"summary":"Get Conversation History From Cache","operationId":"get_conversation_history_from_cache_conv__conversation_id__cache_get","parameters":[{"required":true,"schema":{"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/vanish":{"delete":{"tags":["conversation"],"summary":"Vanish Conversation","description":"硬删除:删除数据库和账号中的对话和历史记录","operationId":"vanish_conversation_conv__conversation_id__vanish_delete","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/assign/{username}":{"patch":{"tags":["conversation"],"summary":"Assign Conversation","operationId":"assign_conversation_conv__conversation_id__assign__username__patch","parameters":[{"required":true,"schema":{"type":"string","title":"Username"},"name":"username","in":"path"},{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/gen_title":{"patch":{"tags":["conversation"],"summary":"Generate Conversation Title","operationId":"generate_conversation_title_conv__conversation_id__gen_title_patch","parameters":[{"required":true,"schema":{"anyOf":[{"type":"string"},{"type":"string","format":"uuid"}],"title":"Conversation Id"},"name":"conversation_id","in":"path"},{"required":true,"schema":{"type":"string","title":"Message Id"},"name":"message_id","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/conv/{conversation_id}/interpreter":{"get":{"tags":["conversation"],"summary":"Get Conversation Interpreter Info","operationId":"get_conversation_interpreter_info_conv__conversation_id__interpreter_get","parameters":[{"required":true,"schema":{"type":"string","title":"Conversation Id"},"name":"conversation_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conv/{conversation_id}/interpreter/download-url":{"get":{"tags":["conversation"],"summary":"Get Conversation Interpreter Download Url","operationId":"get_conversation_interpreter_download_url_conv__conversation_id__interpreter_download_url_get","parameters":[{"required":true,"schema":{"type":"string","title":"Conversation Id"},"name":"conversation_id","in":"path"},{"required":true,"schema":{"type":"string","title":"Message Id"},"name":"message_id","in":"query"},{"required":true,"schema":{"type":"string","title":"Sandbox Path"},"name":"sandbox_path","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/openai-plugins/all":{"get":{"tags":["chat"],"summary":"Get All Openai Web Chat Plugins","operationId":"get_all_openai_web_chat_plugins_chat_openai_plugins_all_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/openai-plugins/installed":{"get":{"tags":["chat"],"summary":"Get Installed Openai Web Chat Plugins","operationId":"get_installed_openai_web_chat_plugins_chat_openai_plugins_installed_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/openai-plugin/{plugin_id}":{"get":{"tags":["chat"],"summary":"Get Openai Web Plugin","operationId":"get_openai_web_plugin_chat_openai_plugin__plugin_id__get","parameters":[{"required":true,"schema":{"type":"string","title":"Plugin Id"},"name":"plugin_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/openai-plugin/{plugin_id}/user-settings":{"patch":{"tags":["chat"],"summary":"Update Chat Plugin User Settings","operationId":"update_chat_plugin_user_settings_chat_openai_plugin__plugin_id__user_settings_patch","parameters":[{"required":true,"schema":{"type":"string","title":"Plugin Id"},"name":"plugin_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenaiChatPluginUserSettings"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/chat/__schema_types":{"get":{"tags":["chat"],"summary":" Predict Schema Types","description":"只用来让 openapi 自动生成 schema,并不实际调用","operationId":"_predict_schema_types_chat___schema_types_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/system/info":{"get":{"tags":["system"],"summary":"Get System Info","operationId":"get_system_info_system_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/stats/request":{"get":{"tags":["system"],"summary":"Get Request Statistics","operationId":"get_request_statistics_system_stats_request_get","parameters":[{"required":false,"schema":{"type":"integer","title":"Granularity","default":1800},"name":"granularity","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/stats/ask":{"get":{"tags":["system"],"summary":"Get Ask Statistics","operationId":"get_ask_statistics_system_stats_ask_get","parameters":[{"required":false,"schema":{"type":"integer","title":"Granularity","default":1800},"name":"granularity","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/logs/server":{"post":{"tags":["system"],"summary":"Get Server Logs","operationId":"get_server_logs_system_logs_server_post","requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/LogFilterOptions"}],"title":"Options","default":{"max_lines":100}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/config":{"get":{"tags":["system"],"summary":"Get Config","operationId":"get_config_system_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"put":{"tags":["system"],"summary":"Update Config","operationId":"update_config_system_config_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigModel"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/credentials":{"get":{"tags":["system"],"summary":"Get Credentials","operationId":"get_credentials_system_credentials_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]},"put":{"tags":["system"],"summary":"Update Credentials","operationId":"update_credentials_system_credentials_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialsModel"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/system/action/sync-openai-web-conv":{"post":{"tags":["system"],"summary":"Sync Openai Web Conversations","operationId":"sync_openai_web_conversations_system_action_sync_openai_web_conv_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/status/common":{"get":{"tags":["status"],"summary":"Get Server Status","description":"普通用户获取服务器状态","operationId":"get_server_status_status_common_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/{file_id}/download-url":{"get":{"tags":["conversation"],"summary":"Get File Download Url","description":"file_id: OpenAI 分配的 id,以 file- 开头","operationId":"get_file_download_url_files__file_id__download_url_get","parameters":[{"required":true,"schema":{"type":"string","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/files/local/upload":{"post":{"tags":["files"],"summary":"Upload File To Local","description":"上传文件到服务器。文件将被保存在服务器上,返回文件信息。\n仅当需要在服务器留存上传的文件时才使用.","operationId":"upload_file_to_local_files_local_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_to_local_files_local_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/local/download/{file_id}":{"get":{"tags":["files"],"summary":"Download File From Local","operationId":"download_file_from_local_files_local_download__file_id__get","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/openai-web/upload-start":{"post":{"tags":["files"],"summary":"Start Upload To Openai","description":"要上传文件到 OpenAI Web,前端需要先调用此接口.\n1. 若最终上传方法是前端直接上传 (Browser -> Azure Blob),则获取上传地址并记录文件信息,响应中 upload_file_info 不为空\n2. 否则的话就是服务端中转上传(Browser -> Local -> Azure Blob,此时响应中 upload_file_info 为空,前端应当:\n a. 先调用 upload_file_to_local 接口上传文件到服务器,拿到文件的 uuid\n b. 再调用 upload_local_file_to_openai_web 接口,通知服务器上传文件到 OpenAI Web","operationId":"start_upload_to_openai_files_openai_web_upload_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenaiChatFileUploadInfo"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/openai-web/upload-complete/{file_id}":{"post":{"tags":["files"],"summary":"Complete Upload To Openai","operationId":"complete_upload_to_openai_files_openai_web_upload_complete__file_id__post","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}},"/files/local/upload-to-openai-web/{file_id}":{"post":{"tags":["files"],"summary":"Upload Local File To Openai Web","description":"将服务器上已有的文件上传到 OpenAI Web(Azure blob)","operationId":"upload_local_file_to_openai_web_files_local_upload_to_openai_web__file_id__post","parameters":[{"required":true,"schema":{"type":"string","format":"uuid","title":"File Id"},"name":"file_id","in":"path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyCookie":[]}]}}},"components":{"schemas":{"AskLogAggregation":{"properties":{"_id":{"$ref":"#/components/schemas/AskLogAggregationID"},"count":{"type":"integer","title":"Count"},"user_ids":{"items":{"type":"integer"},"type":"array","title":"User Ids"},"total_queueing_time":{"type":"number","title":"Total Queueing Time"},"total_ask_time":{"type":"number","title":"Total Ask Time"}},"type":"object","required":["count"],"title":"AskLogAggregation"},"AskLogAggregationID":{"properties":{"start_time":{"type":"string","format":"date-time","title":"Start Time"},"meta":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebAskLogMeta"},{"$ref":"#/components/schemas/OpenaiApiAskLogMeta"}],"title":"Meta"}},"type":"object","required":["start_time"],"title":"AskLogAggregationID"},"AskRequest":{"properties":{"source":{"$ref":"#/components/schemas/ChatSourceTypes"},"model":{"type":"string","title":"Model"},"new_conversation":{"type":"boolean","title":"New Conversation"},"new_title":{"type":"string","title":"New Title"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"parent":{"type":"string","format":"uuid","title":"Parent"},"api_context_message_count":{"type":"integer","minimum":-1.0,"title":"Api Context Message Count","default":-1},"text_content":{"type":"string","title":"Text Content"},"openai_web_plugin_ids":{"items":{"type":"string"},"type":"array","title":"Openai Web Plugin Ids"},"openai_web_attachments":{"items":{"$ref":"#/components/schemas/OpenaiWebAskAttachment"},"type":"array","title":"Openai Web Attachments"},"openai_web_multimodal_image_parts":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMultimodalTextContentImagePart"},"type":"array","title":"Openai Web Multimodal Image Parts"}},"type":"object","required":["source","model","new_conversation","text_content"],"title":"AskRequest"},"AskResponse":{"properties":{"type":{"$ref":"#/components/schemas/AskResponseType"},"tip":{"type":"string","title":"Tip"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"message":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessage"},{"$ref":"#/components/schemas/OpenaiApiChatMessage"}],"title":"Message"},"error_detail":{"type":"string","title":"Error Detail"}},"type":"object","required":["type"],"title":"AskResponse"},"AskResponseType":{"type":"string","enum":["waiting","queueing","message","error"],"title":"AskResponseType","description":"An enumeration."},"AuthSetting":{"properties":{"jwt_secret":{"type":"string","title":"Jwt Secret","default":"MODIFY_THIS_TO_RANDOM_SECURE_STRING"},"jwt_lifetime_seconds":{"type":"integer","minimum":1.0,"title":"Jwt Lifetime Seconds","default":259200},"cookie_max_age":{"type":"integer","minimum":1.0,"title":"Cookie Max Age","default":259200},"user_secret":{"type":"string","title":"User Secret","default":"MODIFY_THIS_TO_ANOTHER_RANDOM_SECURE_STRING"}},"type":"object","title":"AuthSetting"},"BaseChatMessage":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"source":{"type":"string","enum":["openai_web","openai_api"],"title":"Source"},"role":{"anyOf":[{"type":"string","enum":["system","user","assistant","tool"]},{"type":"string"}],"title":"Role"},"author_name":{"anyOf":[{"type":"string","enum":["browser","python"]},{"type":"string"}],"title":"Author Name"},"model":{"type":"string","title":"Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"parent":{"type":"string","format":"uuid","title":"Parent"},"children":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Children"},"content":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageTextContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageMultimodalTextContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageCodeContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageExecutionOutputContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageStderrContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherBrowsingDisplayContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherQuoteContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageSystemErrorContent"}]},{"$ref":"#/components/schemas/OpenaiApiChatMessageTextContent"},{"type":"string"}],"title":"Content"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadata"},{"$ref":"#/components/schemas/OpenaiApiChatMessageMetadata"}],"title":"Metadata"}},"type":"object","required":["id","source","role","children"],"title":"BaseChatMessage"},"BaseConversationHistory":{"properties":{"_id":{"type":"string","format":"uuid","title":" Id"},"source":{"type":"string","enum":["openai_web","openai_api"],"title":"Source"},"title":{"type":"string","title":"Title"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"},"mapping":{"additionalProperties":{"$ref":"#/components/schemas/BaseChatMessage"},"type":"object","title":"Mapping"},"current_node":{"type":"string","format":"uuid","title":"Current Node"},"current_model":{"type":"string","title":"Current Model"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebConversationHistoryMeta"},{"$ref":"#/components/schemas/OpenaiApiConversationHistoryMeta"}],"title":"Metadata"}},"type":"object","required":["source","title","create_time","update_time","mapping"],"title":"BaseConversationHistory"},"BaseConversationSchema":{"properties":{"id":{"type":"integer","title":"Id","default":-1},"source":{"$ref":"#/components/schemas/ChatSourceTypes"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"integer","title":"User Id"},"is_valid":{"type":"boolean","title":"Is Valid","default":true},"current_model":{"type":"string","title":"Current Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"}},"type":"object","required":["source"],"title":"BaseConversationSchema"},"Body_auth_jwt_login_auth_login_post":{"properties":{"grant_type":{"type":"string","pattern":"password","title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"type":"string","title":"Client Id"},"client_secret":{"type":"string","title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_auth_jwt_login_auth_login_post"},"Body_upload_file_to_local_files_local_upload_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_file_to_local_files_local_upload_post"},"ChatSourceTypes":{"type":"string","enum":["openai_web","openai_api"],"title":"ChatSourceTypes","description":"An enumeration."},"CommonSetting":{"properties":{"print_sql":{"type":"boolean","title":"Print Sql","default":false},"create_initial_admin_user":{"type":"boolean","title":"Create Initial Admin User","default":true},"initial_admin_user_username":{"type":"string","title":"Initial Admin User Username","default":"admin"},"initial_admin_user_password":{"type":"string","title":"Initial Admin User Password","default":"password"}},"type":"object","title":"CommonSetting"},"CommonStatusSchema":{"properties":{"active_user_in_5m":{"type":"integer","title":"Active User In 5M"},"active_user_in_1h":{"type":"integer","title":"Active User In 1H"},"active_user_in_1d":{"type":"integer","title":"Active User In 1D"},"is_chatbot_busy":{"type":"boolean","title":"Is Chatbot Busy"},"chatbot_waiting_count":{"type":"integer","title":"Chatbot Waiting Count"},"gpt4_count_in_3_hours":{"type":"integer","title":"Gpt4 Count In 3 Hours"}},"type":"object","title":"CommonStatusSchema"},"ConfigModel":{"properties":{"openai_web":{"allOf":[{"$ref":"#/components/schemas/OpenaiWebChatGPTSetting"}],"title":"Openai Web","default":{"enabled":true,"is_plus_account":true,"common_timeout":20,"ask_timeout":600,"sync_conversations_on_startup":true,"sync_conversations_schedule":false,"sync_conversations_schedule_interval_hours":12,"enabled_models":["gpt_3_5","gpt_4","gpt_4_code_interpreter","gpt_4_plugins","gpt_4_browsing"],"model_code_mapping":{"gpt_3_5":"text-davinci-002-render-sha","gpt_3_5_mobile":"text-davinci-002-render-sha-mobile","gpt_4":"gpt-4","gpt_4_mobile":"gpt-4-mobile","gpt_4_browsing":"gpt-4-browsing","gpt_4_plugins":"gpt-4-plugins","gpt_4_code_interpreter":"gpt-4-code-interpreter"},"file_upload_strategy":"browser_upload_only","enable_uploading_attachments":true,"enable_uploading_multimodal_images":true}},"openai_api":{"allOf":[{"$ref":"#/components/schemas/OpenaiApiSetting"}],"title":"Openai Api","default":{"enabled":true,"openai_base_url":"https://api.openai.com/v1/","connect_timeout":10,"read_timeout":20,"enabled_models":["gpt_3_5","gpt_4"],"model_code_mapping":{"gpt_3_5":"gpt-3.5-turbo","gpt_4":"gpt-4"}}},"common":{"allOf":[{"$ref":"#/components/schemas/CommonSetting"}],"title":"Common","default":{"print_sql":false,"create_initial_admin_user":true,"initial_admin_user_username":"admin","initial_admin_user_password":"password"}},"http":{"allOf":[{"$ref":"#/components/schemas/HttpSetting"}],"title":"Http","default":{"host":"127.0.0.1","port":8000,"cors_allow_origins":["http://localhost:8000","http://localhost:5173","http://127.0.0.1:8000","http://127.0.0.1:5173"]}},"data":{"allOf":[{"$ref":"#/components/schemas/DataSetting"}],"title":"Data","default":{"data_dir":"./data","database_url":"sqlite+aiosqlite:///data/database.db","mongodb_url":"mongodb://cws:password@mongo:27017","mongodb_db_name":"cws","run_migration":false,"max_file_upload_size":104857600}},"auth":{"allOf":[{"$ref":"#/components/schemas/AuthSetting"}],"title":"Auth","default":{"jwt_secret":"MODIFY_THIS_TO_RANDOM_SECURE_STRING","jwt_lifetime_seconds":259200,"cookie_max_age":259200,"user_secret":"MODIFY_THIS_TO_ANOTHER_RANDOM_SECURE_STRING"}},"stats":{"allOf":[{"$ref":"#/components/schemas/StatsSetting"}],"title":"Stats","default":{"ask_stats_ttl":7776000,"request_stats_ttl":2592000,"request_stats_filter_keywords":["/status"]}},"log":{"allOf":[{"$ref":"#/components/schemas/LogSetting"}],"title":"Log","default":{"console_log_level":"INFO"}}},"type":"object","title":"ConfigModel"},"CredentialsModel":{"properties":{"openai_web_access_token":{"type":"string","title":"Openai Web Access Token"},"openai_api_key":{"type":"string","title":"Openai Api Key"}},"type":"object","title":"CredentialsModel"},"CustomOpenaiApiSettings":{"properties":{"url":{"type":"string","title":"Url"},"key":{"type":"string","title":"Key"}},"type":"object","title":"CustomOpenaiApiSettings"},"DailyTimeSlot":{"properties":{"start_time":{"type":"string","format":"time","title":"Start Time","description":"每天可使用的开始时间"},"end_time":{"type":"string","format":"time","title":"End Time","description":"每天可使用的结束时间"}},"type":"object","required":["start_time","end_time"],"title":"DailyTimeSlot"},"DataSetting":{"properties":{"data_dir":{"type":"string","title":"Data Dir","default":"./data"},"database_url":{"type":"string","title":"Database Url","default":"sqlite+aiosqlite:///data/database.db"},"mongodb_url":{"type":"string","title":"Mongodb Url","default":"mongodb://cws:password@mongo:27017"},"mongodb_db_name":{"type":"string","title":"Mongodb Db Name","default":"cws"},"run_migration":{"type":"boolean","title":"Run Migration","default":false},"max_file_upload_size":{"type":"integer","minimum":0.0,"title":"Max File Upload Size","default":104857600}},"type":"object","title":"DataSetting"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HttpSetting":{"properties":{"host":{"type":"string","title":"Host","default":"127.0.0.1"},"port":{"type":"integer","maximum":65535.0,"minimum":1.0,"title":"Port","default":8000},"cors_allow_origins":{"items":{"type":"string"},"type":"array","title":"Cors Allow Origins","default":["http://localhost:8000","http://localhost:5173","http://127.0.0.1:8000","http://127.0.0.1:5173"]}},"type":"object","title":"HttpSetting"},"LogFilterOptions":{"properties":{"max_lines":{"type":"integer","title":"Max Lines","default":100},"exclude_keywords":{"items":{"type":"string"},"type":"array","title":"Exclude Keywords"}},"type":"object","title":"LogFilterOptions"},"LogSetting":{"properties":{"console_log_level":{"type":"string","enum":["INFO","DEBUG","WARNING"],"title":"Console Log Level","default":"INFO"}},"type":"object","title":"LogSetting"},"OpenaiApiAskLogMeta":{"properties":{"source":{"type":"string","enum":["openai_api"],"title":"Source"},"model":{"$ref":"#/components/schemas/OpenaiApiChatModels"}},"type":"object","required":["source","model"],"title":"OpenaiApiAskLogMeta"},"OpenaiApiChatMessage":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"source":{"type":"string","enum":["openai_api"],"title":"Source"},"role":{"anyOf":[{"type":"string","enum":["system","user","assistant","tool"]},{"type":"string"}],"title":"Role"},"author_name":{"anyOf":[{"type":"string","enum":["browser","python"]},{"type":"string"}],"title":"Author Name"},"model":{"type":"string","title":"Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"parent":{"type":"string","format":"uuid","title":"Parent"},"children":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Children"},"content":{"$ref":"#/components/schemas/OpenaiApiChatMessageTextContent"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadata"},{"$ref":"#/components/schemas/OpenaiApiChatMessageMetadata"}],"title":"Metadata"}},"type":"object","required":["id","source","role","children"],"title":"OpenaiApiChatMessage"},"OpenaiApiChatMessageMetadata":{"properties":{"source":{"type":"string","enum":["openai_api"],"title":"Source"},"usage":{"$ref":"#/components/schemas/OpenaiChatResponseUsage"},"finish_reason":{"type":"string","title":"Finish Reason"}},"type":"object","required":["source"],"title":"OpenaiApiChatMessageMetadata"},"OpenaiApiChatMessageTextContent":{"properties":{"content_type":{"type":"string","enum":["text"],"title":"Content Type"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type","text"],"title":"OpenaiApiChatMessageTextContent"},"OpenaiApiChatModels":{"type":"string","enum":["gpt_3_5","gpt_4"],"title":"OpenaiApiChatModels","description":"An enumeration."},"OpenaiApiConversationHistoryDocument":{"properties":{"_id":{"type":"string","format":"uuid","title":" Id"},"source":{"type":"string","enum":["openai_api"],"title":"Source"},"title":{"type":"string","title":"Title"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"},"mapping":{"additionalProperties":{"$ref":"#/components/schemas/OpenaiApiChatMessage"},"type":"object","title":"Mapping"},"current_node":{"type":"string","format":"uuid","title":"Current Node"},"current_model":{"type":"string","title":"Current Model"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebConversationHistoryMeta"},{"$ref":"#/components/schemas/OpenaiApiConversationHistoryMeta"}],"title":"Metadata"}},"type":"object","required":["source","title","create_time","update_time","mapping"],"title":"OpenaiApiConversationHistoryDocument","description":"Document Mapping class.\n\nFields:\n\n- `id` - MongoDB document ObjectID \"_id\" field.\nMapped to the PydanticObjectId class"},"OpenaiApiConversationHistoryMeta":{"properties":{"source":{"type":"string","enum":["openai_api"],"title":"Source"}},"type":"object","required":["source"],"title":"OpenaiApiConversationHistoryMeta"},"OpenaiApiConversationSchema":{"properties":{"id":{"type":"integer","title":"Id","default":-1},"source":{"type":"string","enum":["openai_api"],"title":"Source"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"integer","title":"User Id"},"is_valid":{"type":"boolean","title":"Is Valid","default":true},"current_model":{"type":"string","title":"Current Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"}},"type":"object","required":["source"],"title":"OpenaiApiConversationSchema"},"OpenaiApiPerModelAskCount":{"additionalProperties":{"type":"integer"},"type":"object","title":"OpenaiApiPerModelAskCount","default":{"gpt_3_5":0,"gpt_4":0}},"OpenaiApiSetting":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"openai_base_url":{"type":"string","title":"Openai Base Url","default":"https://api.openai.com/v1/"},"proxy":{"type":"string","title":"Proxy"},"connect_timeout":{"type":"integer","minimum":1.0,"title":"Connect Timeout","default":10},"read_timeout":{"type":"integer","minimum":1.0,"title":"Read Timeout","default":20},"enabled_models":{"items":{"$ref":"#/components/schemas/OpenaiApiChatModels"},"type":"array","default":["gpt_3_5","gpt_4"]},"model_code_mapping":{"additionalProperties":{"type":"string"},"type":"object","title":"Model Code Mapping","default":{"gpt_3_5":"gpt-3.5-turbo","gpt_4":"gpt-4"}}},"type":"object","title":"OpenaiApiSetting"},"OpenaiApiSourceSettingSchema":{"properties":{"allow_to_use":{"type":"boolean","title":"Allow To Use"},"valid_until":{"type":"string","format":"date-time","title":"Valid Until"},"max_conv_count":{"type":"integer","title":"Max Conv Count"},"total_ask_count":{"type":"integer","title":"Total Ask Count"},"rate_limits":{"items":{"$ref":"#/components/schemas/TimeWindowRateLimit"},"type":"array","title":"Rate Limits"},"daily_available_time_slots":{"items":{"$ref":"#/components/schemas/DailyTimeSlot"},"type":"array","title":"Daily Available Time Slots"},"available_models":{"items":{"$ref":"#/components/schemas/OpenaiApiChatModels"},"type":"array"},"per_model_ask_count":{"$ref":"#/components/schemas/OpenaiApiPerModelAskCount"},"allow_custom_openai_api":{"type":"boolean","title":"Allow Custom Openai Api"},"custom_openai_api_settings":{"$ref":"#/components/schemas/CustomOpenaiApiSettings"}},"type":"object","required":["allow_to_use","max_conv_count","total_ask_count","rate_limits","daily_available_time_slots","available_models","per_model_ask_count","allow_custom_openai_api","custom_openai_api_settings"],"title":"OpenaiApiSourceSettingSchema"},"OpenaiChatFileUploadInfo":{"properties":{"file_name":{"type":"string","title":"File Name"},"file_size":{"type":"integer","title":"File Size"},"use_case":{"type":"string","enum":["ace_upload","multimodal"],"title":"Use Case"}},"type":"object","required":["file_name","file_size","use_case"],"title":"OpenaiChatFileUploadInfo"},"OpenaiChatInterpreterInfo":{"properties":{"kernel_started":{"type":"boolean","title":"Kernel Started"},"time_remaining_ms":{"type":"integer","title":"Time Remaining Ms"}},"type":"object","title":"OpenaiChatInterpreterInfo"},"OpenaiChatPlugin":{"properties":{"id":{"type":"string","title":"Id"},"namespace":{"type":"string","title":"Namespace"},"manifest":{"$ref":"#/components/schemas/OpenaiChatPluginManifest"},"categories":{"items":{"$ref":"#/components/schemas/OpenaiChatPluginCategory"},"type":"array","title":"Categories"},"domain":{"type":"string","title":"Domain"},"status":{"anyOf":[{"type":"string","enum":["approved"]},{"type":"string"}],"title":"Status"},"user_settings":{"anyOf":[{"$ref":"#/components/schemas/OpenaiChatPluginUserSettings"},{"type":"object"}],"title":"User Settings"},"oauth_client_id":{"type":"string","title":"Oauth Client Id"}},"type":"object","title":"OpenaiChatPlugin"},"OpenaiChatPluginCategory":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","title":"Title"}},"type":"object","title":"OpenaiChatPluginCategory"},"OpenaiChatPluginManifest":{"properties":{"api":{"type":"object","title":"Api"},"auth":{"type":"object","title":"Auth"},"logo_url":{"type":"string","title":"Logo Url"},"contact_email":{"type":"string","title":"Contact Email"},"schema_version":{"type":"string","title":"Schema Version"},"name_for_model":{"type":"string","title":"Name For Model"},"name_for_human":{"type":"string","title":"Name For Human"},"description_for_model":{"type":"string","title":"Description For Model"},"description_for_human":{"type":"string","title":"Description For Human"},"legal_info_url":{"type":"string","title":"Legal Info Url"}},"type":"object","title":"OpenaiChatPluginManifest"},"OpenaiChatPluginUserSettings":{"properties":{"is_authenticated":{"type":"boolean","title":"Is Authenticated"},"is_installed":{"type":"boolean","title":"Is Installed"}},"type":"object","title":"OpenaiChatPluginUserSettings"},"OpenaiChatResponseUsage":{"properties":{"prompt_tokens":{"type":"integer","title":"Prompt Tokens"},"completion_tokens":{"type":"integer","title":"Completion Tokens"}},"type":"object","title":"OpenaiChatResponseUsage"},"OpenaiWebAskAttachment":{"properties":{"name":{"type":"string","title":"Name"},"id":{"type":"string","title":"Id"},"size":{"type":"integer","title":"Size"}},"type":"object","required":["name","id","size"],"title":"OpenaiWebAskAttachment"},"OpenaiWebAskLogMeta":{"properties":{"source":{"type":"string","enum":["openai_web"],"title":"Source"},"model":{"$ref":"#/components/schemas/OpenaiWebChatModels"}},"type":"object","required":["source","model"],"title":"OpenaiWebAskLogMeta"},"OpenaiWebChatGPTSetting":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":true},"is_plus_account":{"type":"boolean","title":"Is Plus Account","default":true},"chatgpt_base_url":{"type":"string","title":"Chatgpt Base Url"},"proxy":{"type":"string","title":"Proxy"},"common_timeout":{"type":"integer","minimum":1.0,"title":"Common Timeout","default":20},"ask_timeout":{"type":"integer","minimum":1.0,"title":"Ask Timeout","default":600},"sync_conversations_on_startup":{"type":"boolean","title":"Sync Conversations On Startup","default":true},"sync_conversations_schedule":{"type":"boolean","title":"Sync Conversations Schedule","default":false},"sync_conversations_schedule_interval_hours":{"type":"integer","minimum":1.0,"title":"Sync Conversations Schedule Interval Hours","default":12},"enabled_models":{"items":{"$ref":"#/components/schemas/OpenaiWebChatModels"},"type":"array","default":["gpt_3_5","gpt_4","gpt_4_code_interpreter","gpt_4_plugins","gpt_4_browsing"]},"model_code_mapping":{"additionalProperties":{"type":"string"},"type":"object","title":"Model Code Mapping","default":{"gpt_3_5":"text-davinci-002-render-sha","gpt_3_5_mobile":"text-davinci-002-render-sha-mobile","gpt_4":"gpt-4","gpt_4_mobile":"gpt-4-mobile","gpt_4_browsing":"gpt-4-browsing","gpt_4_plugins":"gpt-4-plugins","gpt_4_code_interpreter":"gpt-4-code-interpreter"}},"file_upload_strategy":{"allOf":[{"$ref":"#/components/schemas/OpenaiWebFileUploadStrategyOption"}],"default":"browser_upload_only"},"enable_uploading_attachments":{"type":"boolean","title":"Enable Uploading Attachments","default":true},"enable_uploading_multimodal_images":{"type":"boolean","title":"Enable Uploading Multimodal Images","default":true}},"type":"object","title":"OpenaiWebChatGPTSetting"},"OpenaiWebChatMessage":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"source":{"type":"string","enum":["openai_web"],"title":"Source"},"role":{"anyOf":[{"type":"string","enum":["system","user","assistant","tool"]},{"type":"string"}],"title":"Role"},"author_name":{"anyOf":[{"type":"string","enum":["browser","python"]},{"type":"string"}],"title":"Author Name"},"model":{"type":"string","title":"Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"parent":{"type":"string","format":"uuid","title":"Parent"},"children":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Children"},"content":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageTextContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageMultimodalTextContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageCodeContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageExecutionOutputContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageStderrContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherBrowsingDisplayContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageTetherQuoteContent"},{"$ref":"#/components/schemas/OpenaiWebChatMessageSystemErrorContent"}],"title":"Content"},"metadata":{"anyOf":[{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadata"},{"$ref":"#/components/schemas/OpenaiApiChatMessageMetadata"}],"title":"Metadata"}},"type":"object","required":["id","source","role","children"],"title":"OpenaiWebChatMessage"},"OpenaiWebChatMessageCodeContent":{"properties":{"content_type":{"type":"string","enum":["code"],"title":"Content Type"},"language":{"type":"string","title":"Language"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageCodeContent"},"OpenaiWebChatMessageExecutionOutputContent":{"properties":{"content_type":{"type":"string","enum":["execution_output"],"title":"Content Type"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageExecutionOutputContent"},"OpenaiWebChatMessageMetadata":{"properties":{"source":{"type":"string","enum":["openai_web"],"title":"Source"},"finish_details":{"type":"object","title":"Finish Details"},"weight":{"type":"number","title":"Weight"},"end_turn":{"type":"boolean","title":"End Turn"},"message_status":{"type":"string","title":"Message Status"},"recipient":{"anyOf":[{"type":"string","enum":["all","browser","python"]},{"type":"string"}],"title":"Recipient"},"fallback_content":{"title":"Fallback Content"},"invoked_plugin":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataPlugin"},"command":{"anyOf":[{"type":"string","enum":["search"]},{"type":"string"}],"title":"Command"},"args":{"items":{"type":"string"},"type":"array","title":"Args"},"status":{"anyOf":[{"type":"string","enum":["finished"]},{"type":"string"}],"title":"Status"},"_cite_metadata":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCite"},"citations":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCitation"},"type":"array","title":"Citations"},"attachments":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataAttachment"},"type":"array","title":"Attachments"},"is_complete":{"type":"boolean","title":"Is Complete"},"aggregate_result":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataAggregateResult"}},"type":"object","required":["source"],"title":"OpenaiWebChatMessageMetadata"},"OpenaiWebChatMessageMetadataAggregateResult":{"properties":{"status":{"anyOf":[{"type":"string","enum":["failed_with_in_kernel_exception","success"]},{"type":"string"}],"title":"Status"},"run_id":{"type":"string","title":"Run Id"},"start_time":{"type":"number","title":"Start Time"},"update_time":{"type":"number","title":"Update Time"},"end_time":{"type":"number","title":"End Time"},"final_expression_output":{"title":"Final Expression Output"},"code":{"type":"string","title":"Code"},"in_kernel_exception":{"type":"object","title":"In Kernel Exception"},"messages":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataAggregateResultMessage"},"type":"array","title":"Messages"},"jupyter_messages":{"items":{},"type":"array","title":"Jupyter Messages"}},"type":"object","title":"OpenaiWebChatMessageMetadataAggregateResult"},"OpenaiWebChatMessageMetadataAggregateResultMessage":{"properties":{"message_type":{"anyOf":[{"type":"string","enum":["image","stream"]},{"type":"string"}],"title":"Message Type"},"time":{"type":"number","title":"Time"},"sender":{"anyOf":[{"type":"string","enum":["server"]},{"type":"string"}],"title":"Sender"},"image_url":{"type":"string","title":"Image Url"},"stream_name":{"type":"string","title":"Stream Name"},"text":{"type":"string","title":"Text"}},"type":"object","title":"OpenaiWebChatMessageMetadataAggregateResultMessage"},"OpenaiWebChatMessageMetadataAttachment":{"properties":{"name":{"type":"string","title":"Name"},"id":{"type":"string","title":"Id"},"size":{"type":"integer","title":"Size"}},"type":"object","title":"OpenaiWebChatMessageMetadataAttachment"},"OpenaiWebChatMessageMetadataCitation":{"properties":{"start_ix":{"type":"integer","title":"Start Ix"},"end_ix":{"type":"integer","title":"End Ix"},"metadata":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCiteData"}},"type":"object","title":"OpenaiWebChatMessageMetadataCitation"},"OpenaiWebChatMessageMetadataCite":{"properties":{"citation_format":{"type":"object","title":"Citation Format"},"metadata_list":{"items":{"$ref":"#/components/schemas/OpenaiWebChatMessageMetadataCiteData"},"type":"array","title":"Metadata List"}},"type":"object","title":"OpenaiWebChatMessageMetadataCite"},"OpenaiWebChatMessageMetadataCiteData":{"properties":{"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"},"text":{"type":"string","title":"Text"}},"type":"object","title":"OpenaiWebChatMessageMetadataCiteData"},"OpenaiWebChatMessageMetadataPlugin":{"properties":{"http_response_status":{"type":"integer","title":"Http Response Status"},"namespace":{"type":"string","title":"Namespace"},"plugin_id":{"type":"string","title":"Plugin Id"},"type":{"type":"string","title":"Type"}},"type":"object","title":"OpenaiWebChatMessageMetadataPlugin"},"OpenaiWebChatMessageMultimodalTextContent":{"properties":{"content_type":{"type":"string","enum":["multimodal_text"],"title":"Content Type"},"parts":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/OpenaiWebChatMessageMultimodalTextContentImagePart"},{}]},"type":"array","title":"Parts"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageMultimodalTextContent"},"OpenaiWebChatMessageMultimodalTextContentImagePart":{"properties":{"asset_pointer":{"type":"string","title":"Asset Pointer"},"size_bytes":{"type":"integer","title":"Size Bytes"},"width":{"type":"integer","title":"Width"},"height":{"type":"integer","title":"Height"}},"type":"object","title":"OpenaiWebChatMessageMultimodalTextContentImagePart"},"OpenaiWebChatMessageStderrContent":{"properties":{"content_type":{"type":"string","enum":["stderr"],"title":"Content Type"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageStderrContent"},"OpenaiWebChatMessageSystemErrorContent":{"properties":{"content_type":{"type":"string","enum":["system_error"],"title":"Content Type"},"name":{"anyOf":[{"type":"string","enum":["tool_error"]},{"type":"string"}],"title":"Name"},"text":{"type":"string","title":"Text"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageSystemErrorContent"},"OpenaiWebChatMessageTetherBrowsingDisplayContent":{"properties":{"content_type":{"type":"string","enum":["tether_browsing_display"],"title":"Content Type"},"result":{"type":"string","title":"Result"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageTetherBrowsingDisplayContent"},"OpenaiWebChatMessageTetherQuoteContent":{"properties":{"content_type":{"type":"string","enum":["tether_quote"],"title":"Content Type"},"url":{"type":"string","title":"Url"},"domain":{"type":"string","title":"Domain"},"text":{"type":"string","title":"Text"},"title":{"type":"string","title":"Title"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageTetherQuoteContent"},"OpenaiWebChatMessageTextContent":{"properties":{"content_type":{"type":"string","enum":["text"],"title":"Content Type"},"parts":{"items":{"type":"string"},"type":"array","title":"Parts"}},"type":"object","required":["content_type"],"title":"OpenaiWebChatMessageTextContent"},"OpenaiWebChatModels":{"type":"string","enum":["gpt_3_5","gpt_3_5_mobile","gpt_4","gpt_4_mobile","gpt_4_browsing","gpt_4_plugins","gpt_4_code_interpreter"],"title":"OpenaiWebChatModels","description":"An enumeration."},"OpenaiWebChatStatus":{"type":"string","enum":["asking","queueing","idling"],"title":"OpenaiWebChatStatus","description":"An enumeration."},"OpenaiWebConversationHistoryDocument":{"properties":{"_id":{"type":"string","format":"uuid","title":" Id"},"source":{"type":"string","enum":["openai_web"],"title":"Source"},"title":{"type":"string","title":"Title"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"},"mapping":{"additionalProperties":{"$ref":"#/components/schemas/OpenaiWebChatMessage"},"type":"object","title":"Mapping"},"current_node":{"type":"string","format":"uuid","title":"Current Node"},"current_model":{"type":"string","title":"Current Model"},"metadata":{"$ref":"#/components/schemas/OpenaiWebConversationHistoryMeta"}},"type":"object","required":["source","title","create_time","update_time","mapping"],"title":"OpenaiWebConversationHistoryDocument","description":"Document Mapping class.\n\nFields:\n\n- `id` - MongoDB document ObjectID \"_id\" field.\nMapped to the PydanticObjectId class"},"OpenaiWebConversationHistoryMeta":{"properties":{"source":{"type":"string","enum":["openai_web"],"title":"Source"},"moderation_results":{"items":{},"type":"array","title":"Moderation Results"},"plugin_ids":{"items":{"type":"string"},"type":"array","title":"Plugin Ids"}},"type":"object","required":["source"],"title":"OpenaiWebConversationHistoryMeta"},"OpenaiWebConversationSchema":{"properties":{"id":{"type":"integer","title":"Id","default":-1},"source":{"type":"string","enum":["openai_web"],"title":"Source"},"conversation_id":{"type":"string","format":"uuid","title":"Conversation Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"integer","title":"User Id"},"is_valid":{"type":"boolean","title":"Is Valid","default":true},"current_model":{"type":"string","title":"Current Model"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"update_time":{"type":"string","format":"date-time","title":"Update Time"}},"type":"object","required":["source"],"title":"OpenaiWebConversationSchema"},"OpenaiWebFileUploadStrategyOption":{"type":"string","enum":["disable_upload","server_upload_only","browser_upload_only","browser_upload_when_file_size_exceed"],"title":"OpenaiWebFileUploadStrategyOption","description":"An enumeration."},"OpenaiWebPerModelAskCount":{"additionalProperties":{"type":"integer"},"type":"object","title":"OpenaiWebPerModelAskCount","default":{"gpt_3_5":0,"gpt_3_5_mobile":0,"gpt_4":0,"gpt_4_mobile":0,"gpt_4_browsing":0,"gpt_4_plugins":0,"gpt_4_code_interpreter":0}},"OpenaiWebSourceSettingSchema":{"properties":{"allow_to_use":{"type":"boolean","title":"Allow To Use"},"valid_until":{"type":"string","format":"date-time","title":"Valid Until"},"max_conv_count":{"type":"integer","title":"Max Conv Count"},"total_ask_count":{"type":"integer","title":"Total Ask Count"},"rate_limits":{"items":{"$ref":"#/components/schemas/TimeWindowRateLimit"},"type":"array","title":"Rate Limits"},"daily_available_time_slots":{"items":{"$ref":"#/components/schemas/DailyTimeSlot"},"type":"array","title":"Daily Available Time Slots"},"available_models":{"items":{"$ref":"#/components/schemas/OpenaiWebChatModels"},"type":"array"},"per_model_ask_count":{"$ref":"#/components/schemas/OpenaiWebPerModelAskCount"},"allow_uploading_attachments":{"type":"boolean","title":"Allow Uploading Attachments"},"allow_uploading_multimodal_images":{"type":"boolean","title":"Allow Uploading Multimodal Images"}},"type":"object","required":["allow_to_use","max_conv_count","total_ask_count","rate_limits","daily_available_time_slots","available_models","per_model_ask_count","allow_uploading_attachments","allow_uploading_multimodal_images"],"title":"OpenaiWebSourceSettingSchema"},"RequestLogAggregation":{"properties":{"_id":{"$ref":"#/components/schemas/RequestLogAggregationID"},"count":{"type":"integer","title":"Count"},"user_ids":{"items":{"type":"integer"},"type":"array","title":"User Ids"},"avg_elapsed_ms":{"type":"number","title":"Avg Elapsed Ms"}},"type":"object","required":["_id","count"],"title":"RequestLogAggregation"},"RequestLogAggregationID":{"properties":{"start_time":{"type":"string","format":"date-time","title":"Start Time"},"route_path":{"type":"string","title":"Route Path"},"method":{"type":"string","title":"Method"}},"type":"object","title":"RequestLogAggregationID"},"StartUploadResponseSchema":{"properties":{"strategy":{"$ref":"#/components/schemas/OpenaiWebFileUploadStrategyOption"},"file_max_size":{"type":"integer","title":"File Max Size"},"upload_file_info":{"$ref":"#/components/schemas/UploadedFileInfoSchema"}},"type":"object","required":["strategy","file_max_size"],"title":"StartUploadResponseSchema"},"StatsSetting":{"properties":{"ask_stats_ttl":{"type":"integer","title":"Ask Stats Ttl","default":7776000},"request_stats_ttl":{"type":"integer","title":"Request Stats Ttl","default":2592000},"request_stats_filter_keywords":{"items":{"type":"string"},"type":"array","title":"Request Stats Filter Keywords","default":["/status"]}},"type":"object","title":"StatsSetting"},"SystemInfo":{"properties":{"startup_time":{"type":"number","title":"Startup Time"},"total_user_count":{"type":"integer","title":"Total User Count"},"total_conversation_count":{"type":"integer","title":"Total Conversation Count"},"valid_conversation_count":{"type":"integer","title":"Valid Conversation Count"}},"type":"object","required":["startup_time","total_user_count","total_conversation_count","valid_conversation_count"],"title":"SystemInfo"},"TimeWindowRateLimit":{"properties":{"window_seconds":{"type":"integer","title":"Window Seconds","description":"时间窗口大小,单位为秒"},"max_requests":{"type":"integer","title":"Max Requests","description":"在给定时间窗口内最多的请求次数"}},"type":"object","required":["window_seconds","max_requests"],"title":"TimeWindowRateLimit"},"UploadedFileInfoSchema":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"original_filename":{"type":"string","title":"Original Filename"},"size":{"type":"integer","title":"Size"},"storage_path":{"type":"string","title":"Storage Path"},"content_type":{"type":"string","title":"Content Type"},"upload_time":{"type":"string","format":"date-time","title":"Upload Time"},"uploader_id":{"type":"integer","title":"Uploader Id"},"openai_web_info":{"$ref":"#/components/schemas/UploadedFileOpenaiWebInfo"}},"type":"object","required":["id","original_filename","size","upload_time","uploader_id"],"title":"UploadedFileInfoSchema"},"UploadedFileOpenaiWebInfo":{"properties":{"file_id":{"type":"string","title":"File Id"},"use_case":{"anyOf":[{"type":"string","enum":["ace_upload","multimodal"]},{"type":"string"}],"title":"Use Case"},"upload_url":{"type":"string","title":"Upload Url","description":"上传文件的url, 上传后应清空该字段"},"download_url":{"type":"string","title":"Download Url"}},"type":"object","title":"UploadedFileOpenaiWebInfo"},"UserCreate":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"},"is_active":{"type":"boolean","title":"Is Active","default":true},"is_superuser":{"type":"boolean","title":"Is Superuser","default":false},"is_verified":{"type":"boolean","title":"Is Verified","default":false},"username":{"type":"string","title":"Username"},"nickname":{"type":"string","title":"Nickname"},"avatar":{"type":"string","title":"Avatar"},"remark":{"type":"string","title":"Remark"}},"type":"object","required":["email","password","username","nickname"],"title":"UserCreate"},"UserRead":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"username":{"type":"string","title":"Username"},"nickname":{"type":"string","title":"Nickname"},"last_active_time":{"type":"string","format":"date-time","title":"Last Active Time"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"avatar":{"type":"string","title":"Avatar"},"setting":{"$ref":"#/components/schemas/UserSettingSchema"}},"type":"object","required":["id","email","is_active","is_superuser","is_verified","username","nickname","create_time","setting"],"title":"UserRead","description":"Base User model."},"UserReadAdmin":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"username":{"type":"string","title":"Username"},"nickname":{"type":"string","title":"Nickname"},"last_active_time":{"type":"string","format":"date-time","title":"Last Active Time"},"create_time":{"type":"string","format":"date-time","title":"Create Time"},"avatar":{"type":"string","title":"Avatar"},"setting":{"$ref":"#/components/schemas/UserSettingSchema"},"remark":{"type":"string","title":"Remark"}},"type":"object","required":["id","email","is_active","is_superuser","is_verified","username","nickname","create_time","setting"],"title":"UserReadAdmin","description":"Base User model."},"UserSettingSchema":{"properties":{"id":{"type":"integer","title":"Id"},"user_id":{"type":"integer","title":"User Id"},"credits":{"type":"number","title":"Credits"},"openai_web_chat_status":{"$ref":"#/components/schemas/OpenaiWebChatStatus"},"openai_web":{"$ref":"#/components/schemas/OpenaiWebSourceSettingSchema"},"openai_api":{"$ref":"#/components/schemas/OpenaiApiSourceSettingSchema"}},"type":"object","required":["credits","openai_web_chat_status","openai_web","openai_api"],"title":"UserSettingSchema"},"UserUpdate":{"properties":{"password":{"type":"string","title":"Password"},"email":{"type":"string","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"nickname":{"type":"string","title":"Nickname"},"avatar":{"type":"string","title":"Avatar"}},"type":"object","title":"UserUpdate"},"UserUpdateAdmin":{"properties":{"password":{"type":"string","title":"Password"},"email":{"type":"string","title":"Email"},"is_active":{"type":"boolean","title":"Is Active"},"is_superuser":{"type":"boolean","title":"Is Superuser"},"is_verified":{"type":"boolean","title":"Is Verified"},"nickname":{"type":"string","title":"Nickname"},"avatar":{"type":"string","title":"Avatar"},"username":{"type":"string","title":"Username"},"remark":{"type":"string","title":"Remark"}},"type":"object","title":"UserUpdateAdmin"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"APIKeyCookie":{"type":"apiKey","in":"cookie","name":"cws_user_auth"}}}} \ No newline at end of file diff --git a/frontend/src/types/json/schemas.json b/frontend/src/types/json/schemas.json index 419cc597..6b62b6e8 100644 --- a/frontend/src/types/json/schemas.json +++ b/frontend/src/types/json/schemas.json @@ -218,9 +218,9 @@ "title": "Api Context Message Count", "default": -1 }, - "content": { + "text_content": { "type": "string", - "title": "Content" + "title": "Text Content" }, "openai_web_plugin_ids": { "items": { @@ -255,6 +255,32 @@ }, "type": "array", "title": "Openai Web Attachments" + }, + "openai_web_multimodal_image_parts": { + "items": { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, + "type": "array", + "title": "Openai Web Multimodal Image Parts" } }, "type": "object", @@ -262,7 +288,7 @@ "source", "model", "new_conversation", - "content" + "text_content" ], "title": "AskRequest" }, @@ -383,6 +409,56 @@ ], "title": "OpenaiWebChatMessageTextContent" }, + { + "properties": { + "content_type": { + "type": "string", + "enum": [ + "multimodal_text" + ], + "title": "Content Type" + }, + "parts": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, + {} + ] + }, + "type": "array", + "title": "Parts" + } + }, + "type": "object", + "required": [ + "content_type" + ], + "title": "OpenaiWebChatMessageMultimodalTextContent" + }, { "properties": { "content_type": { @@ -1492,6 +1568,56 @@ ], "title": "OpenaiWebChatMessageTextContent" }, + { + "properties": { + "content_type": { + "type": "string", + "enum": [ + "multimodal_text" + ], + "title": "Content Type" + }, + "parts": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, + {} + ] + }, + "type": "array", + "title": "Parts" + } + }, + "type": "object", + "required": [ + "content_type" + ], + "title": "OpenaiWebChatMessageMultimodalTextContent" + }, { "properties": { "content_type": { @@ -2156,6 +2282,56 @@ ], "title": "OpenaiWebChatMessageTextContent" }, + { + "properties": { + "content_type": { + "type": "string", + "enum": [ + "multimodal_text" + ], + "title": "Content Type" + }, + "parts": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, + {} + ] + }, + "type": "array", + "title": "Parts" + } + }, + "type": "object", + "required": [ + "content_type" + ], + "title": "OpenaiWebChatMessageMultimodalTextContent" + }, { "properties": { "content_type": { @@ -2964,7 +3140,7 @@ "type": "integer", "minimum": 1, "title": "Common Timeout", - "default": 10 + "default": 20 }, "ask_timeout": { "type": "integer", @@ -3043,6 +3219,16 @@ } ], "default": "browser_upload_only" + }, + "enable_uploading_attachments": { + "type": "boolean", + "title": "Enable Uploading Attachments", + "default": true + }, + "enable_uploading_multimodal_images": { + "type": "boolean", + "title": "Enable Uploading Multimodal Images", + "default": true } }, "type": "object", @@ -3053,7 +3239,7 @@ "default": { "enabled": true, "is_plus_account": true, - "common_timeout": 10, + "common_timeout": 20, "ask_timeout": 600, "sync_conversations_on_startup": true, "sync_conversations_schedule": false, @@ -3074,7 +3260,9 @@ "gpt_4_plugins": "gpt-4-plugins", "gpt_4_code_interpreter": "gpt-4-code-interpreter" }, - "file_upload_strategy": "browser_upload_only" + "file_upload_strategy": "browser_upload_only", + "enable_uploading_attachments": true, + "enable_uploading_multimodal_images": true } }, "openai_api": { @@ -3257,6 +3445,11 @@ "title": "Mongodb Url", "default": "mongodb://cws:password@mongo:27017" }, + "mongodb_db_name": { + "type": "string", + "title": "Mongodb Db Name", + "default": "cws" + }, "run_migration": { "type": "boolean", "title": "Run Migration", @@ -3278,6 +3471,7 @@ "data_dir": "./data", "database_url": "sqlite+aiosqlite:///data/database.db", "mongodb_url": "mongodb://cws:password@mongo:27017", + "mongodb_db_name": "cws", "run_migration": false, "max_file_upload_size": 104857600 } @@ -3454,6 +3648,11 @@ "title": "Mongodb Url", "default": "mongodb://cws:password@mongo:27017" }, + "mongodb_db_name": { + "type": "string", + "title": "Mongodb Db Name", + "default": "cws" + }, "run_migration": { "type": "boolean", "title": "Run Migration", @@ -4940,16 +5139,10 @@ "title": "File Size" }, "use_case": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "string", - "enum": [ - "ace_upload" - ] - } + "type": "string", + "enum": [ + "ace_upload", + "multimodal" ], "title": "Use Case" } @@ -5264,7 +5457,7 @@ "type": "integer", "minimum": 1, "title": "Common Timeout", - "default": 10 + "default": 20 }, "ask_timeout": { "type": "integer", @@ -5343,6 +5536,16 @@ } ], "default": "browser_upload_only" + }, + "enable_uploading_attachments": { + "type": "boolean", + "title": "Enable Uploading Attachments", + "default": true + }, + "enable_uploading_multimodal_images": { + "type": "boolean", + "title": "Enable Uploading Multimodal Images", + "default": true } }, "type": "object", @@ -5441,6 +5644,56 @@ ], "title": "OpenaiWebChatMessageTextContent" }, + { + "properties": { + "content_type": { + "type": "string", + "enum": [ + "multimodal_text" + ], + "title": "Content Type" + }, + "parts": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, + {} + ] + }, + "type": "array", + "title": "Parts" + } + }, + "type": "object", + "required": [ + "content_type" + ], + "title": "OpenaiWebChatMessageMultimodalTextContent" + }, { "properties": { "content_type": { @@ -6588,6 +6841,78 @@ "type": "object", "title": "OpenaiWebChatMessageMetadataPlugin" }, + "OpenaiWebChatMessageMultimodalTextContent": { + "properties": { + "content_type": { + "type": "string", + "enum": [ + "multimodal_text" + ], + "title": "Content Type" + }, + "parts": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, + {} + ] + }, + "type": "array", + "title": "Parts" + } + }, + "type": "object", + "required": [ + "content_type" + ], + "title": "OpenaiWebChatMessageMultimodalTextContent" + }, + "OpenaiWebChatMessageMultimodalTextContentImagePart": { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, "OpenaiWebChatMessageStderrContent": { "properties": { "content_type": { @@ -6863,6 +7188,56 @@ ], "title": "OpenaiWebChatMessageTextContent" }, + { + "properties": { + "content_type": { + "type": "string", + "enum": [ + "multimodal_text" + ], + "title": "Content Type" + }, + "parts": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "properties": { + "asset_pointer": { + "type": "string", + "title": "Asset Pointer" + }, + "size_bytes": { + "type": "integer", + "title": "Size Bytes" + }, + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + } + }, + "type": "object", + "title": "OpenaiWebChatMessageMultimodalTextContentImagePart" + }, + {} + ] + }, + "type": "array", + "title": "Parts" + } + }, + "type": "object", + "required": [ + "content_type" + ], + "title": "OpenaiWebChatMessageMultimodalTextContent" + }, { "properties": { "content_type": { @@ -7636,6 +8011,14 @@ "gpt_4_plugins": 0, "gpt_4_code_interpreter": 0 } + }, + "allow_uploading_attachments": { + "type": "boolean", + "title": "Allow Uploading Attachments" + }, + "allow_uploading_multimodal_images": { + "type": "boolean", + "title": "Allow Uploading Multimodal Images" } }, "type": "object", @@ -7646,7 +8029,9 @@ "rate_limits", "daily_available_time_slots", "available_models", - "per_model_ask_count" + "per_model_ask_count", + "allow_uploading_attachments", + "allow_uploading_multimodal_images" ], "title": "OpenaiWebSourceSettingSchema" }, @@ -7768,6 +8153,21 @@ "type": "string", "title": "File Id" }, + "use_case": { + "anyOf": [ + { + "type": "string", + "enum": [ + "ace_upload", + "multimodal" + ] + }, + { + "type": "string" + } + ], + "title": "Use Case" + }, "upload_url": { "type": "string", "title": "Upload Url", @@ -7912,6 +8312,21 @@ "type": "string", "title": "File Id" }, + "use_case": { + "anyOf": [ + { + "type": "string", + "enum": [ + "ace_upload", + "multimodal" + ] + }, + { + "type": "string" + } + ], + "title": "Use Case" + }, "upload_url": { "type": "string", "title": "Upload Url", @@ -7942,6 +8357,21 @@ "type": "string", "title": "File Id" }, + "use_case": { + "anyOf": [ + { + "type": "string", + "enum": [ + "ace_upload", + "multimodal" + ] + }, + { + "type": "string" + } + ], + "title": "Use Case" + }, "upload_url": { "type": "string", "title": "Upload Url", @@ -8177,6 +8607,14 @@ "gpt_4_plugins": 0, "gpt_4_code_interpreter": 0 } + }, + "allow_uploading_attachments": { + "type": "boolean", + "title": "Allow Uploading Attachments" + }, + "allow_uploading_multimodal_images": { + "type": "boolean", + "title": "Allow Uploading Multimodal Images" } }, "type": "object", @@ -8187,7 +8625,9 @@ "rate_limits", "daily_available_time_slots", "available_models", - "per_model_ask_count" + "per_model_ask_count", + "allow_uploading_attachments", + "allow_uploading_multimodal_images" ], "title": "OpenaiWebSourceSettingSchema" }, @@ -8512,6 +8952,14 @@ "gpt_4_plugins": 0, "gpt_4_code_interpreter": 0 } + }, + "allow_uploading_attachments": { + "type": "boolean", + "title": "Allow Uploading Attachments" + }, + "allow_uploading_multimodal_images": { + "type": "boolean", + "title": "Allow Uploading Multimodal Images" } }, "type": "object", @@ -8522,7 +8970,9 @@ "rate_limits", "daily_available_time_slots", "available_models", - "per_model_ask_count" + "per_model_ask_count", + "allow_uploading_attachments", + "allow_uploading_multimodal_images" ], "title": "OpenaiWebSourceSettingSchema" }, @@ -8806,6 +9256,14 @@ "gpt_4_plugins": 0, "gpt_4_code_interpreter": 0 } + }, + "allow_uploading_attachments": { + "type": "boolean", + "title": "Allow Uploading Attachments" + }, + "allow_uploading_multimodal_images": { + "type": "boolean", + "title": "Allow Uploading Multimodal Images" } }, "type": "object", @@ -8816,7 +9274,9 @@ "rate_limits", "daily_available_time_slots", "available_models", - "per_model_ask_count" + "per_model_ask_count", + "allow_uploading_attachments", + "allow_uploading_multimodal_images" ], "title": "OpenaiWebSourceSettingSchema" }, diff --git a/frontend/src/types/openapi.ts b/frontend/src/types/openapi.ts index 56981573..8f963360 100644 --- a/frontend/src/types/openapi.ts +++ b/frontend/src/types/openapi.ts @@ -89,10 +89,6 @@ export interface paths { /** Get Conversation Interpreter Info */ get: operations["get_conversation_interpreter_info_conv__conversation_id__interpreter_get"]; }; - "/conv/files/{file_id}/download-url": { - /** Get File Download Url */ - get: operations["get_file_download_url_conv_files__file_id__download_url_get"]; - }; "/conv/{conversation_id}/interpreter/download-url": { /** Get Conversation Interpreter Download Url */ get: operations["get_conversation_interpreter_download_url_conv__conversation_id__interpreter_download_url_get"]; @@ -159,6 +155,13 @@ export interface paths { */ get: operations["get_server_status_status_common_get"]; }; + "/files/{file_id}/download-url": { + /** + * Get File Download Url + * @description file_id: OpenAI 分配的 id,以 file- 开头 + */ + get: operations["get_file_download_url_files__file_id__download_url_get"]; + }; "/files/local/upload": { /** * Upload File To Local @@ -245,12 +248,14 @@ export interface components { * @default -1 */ api_context_message_count?: number; - /** Content */ - content: string; + /** Text Content */ + text_content: string; /** Openai Web Plugin Ids */ openai_web_plugin_ids?: (string)[]; /** Openai Web Attachments */ openai_web_attachments?: (components["schemas"]["OpenaiWebAskAttachment"])[]; + /** Openai Web Multimodal Image Parts */ + openai_web_multimodal_image_parts?: (components["schemas"]["OpenaiWebChatMessageMultimodalTextContentImagePart"])[]; }; /** AskResponse */ AskResponse: { @@ -327,7 +332,7 @@ export interface components { /** Children */ children: (string)[]; /** Content */ - content?: (components["schemas"]["OpenaiWebChatMessageTextContent"] | components["schemas"]["OpenaiWebChatMessageCodeContent"] | components["schemas"]["OpenaiWebChatMessageExecutionOutputContent"] | components["schemas"]["OpenaiWebChatMessageStderrContent"] | components["schemas"]["OpenaiWebChatMessageTetherBrowsingDisplayContent"] | components["schemas"]["OpenaiWebChatMessageTetherQuoteContent"] | components["schemas"]["OpenaiWebChatMessageSystemErrorContent"]) | components["schemas"]["OpenaiApiChatMessageTextContent"] | string; + content?: (components["schemas"]["OpenaiWebChatMessageTextContent"] | components["schemas"]["OpenaiWebChatMessageMultimodalTextContent"] | components["schemas"]["OpenaiWebChatMessageCodeContent"] | components["schemas"]["OpenaiWebChatMessageExecutionOutputContent"] | components["schemas"]["OpenaiWebChatMessageStderrContent"] | components["schemas"]["OpenaiWebChatMessageTetherBrowsingDisplayContent"] | components["schemas"]["OpenaiWebChatMessageTetherQuoteContent"] | components["schemas"]["OpenaiWebChatMessageSystemErrorContent"]) | components["schemas"]["OpenaiApiChatMessageTextContent"] | string; /** Metadata */ metadata?: components["schemas"]["OpenaiWebChatMessageMetadata"] | components["schemas"]["OpenaiApiChatMessageMetadata"]; }; @@ -481,7 +486,7 @@ export interface components { * @default { * "enabled": true, * "is_plus_account": true, - * "common_timeout": 10, + * "common_timeout": 20, * "ask_timeout": 600, * "sync_conversations_on_startup": true, * "sync_conversations_schedule": false, @@ -502,7 +507,9 @@ export interface components { * "gpt_4_plugins": "gpt-4-plugins", * "gpt_4_code_interpreter": "gpt-4-code-interpreter" * }, - * "file_upload_strategy": "browser_upload_only" + * "file_upload_strategy": "browser_upload_only", + * "enable_uploading_attachments": true, + * "enable_uploading_multimodal_images": true * } */ openai_web?: components["schemas"]["OpenaiWebChatGPTSetting"]; @@ -554,6 +561,7 @@ export interface components { * "data_dir": "./data", * "database_url": "sqlite+aiosqlite:///data/database.db", * "mongodb_url": "mongodb://cws:password@mongo:27017", + * "mongodb_db_name": "cws", * "run_migration": false, * "max_file_upload_size": 104857600 * } @@ -634,6 +642,11 @@ export interface components { * @default mongodb://cws:password@mongo:27017 */ mongodb_url?: string; + /** + * Mongodb Db Name + * @default cws + */ + mongodb_db_name?: string; /** * Run Migration * @default false @@ -936,8 +949,11 @@ export interface components { file_name: string; /** File Size */ file_size: number; - /** Use Case */ - use_case: string | "ace_upload"; + /** + * Use Case + * @enum {string} + */ + use_case: "ace_upload" | "multimodal"; }; /** OpenaiChatInterpreterInfo */ OpenaiChatInterpreterInfo: { @@ -1044,7 +1060,7 @@ export interface components { proxy?: string; /** * Common Timeout - * @default 10 + * @default 20 */ common_timeout?: number; /** @@ -1094,6 +1110,16 @@ export interface components { }; /** @default browser_upload_only */ file_upload_strategy?: components["schemas"]["OpenaiWebFileUploadStrategyOption"]; + /** + * Enable Uploading Attachments + * @default true + */ + enable_uploading_attachments?: boolean; + /** + * Enable Uploading Multimodal Images + * @default true + */ + enable_uploading_multimodal_images?: boolean; }; /** OpenaiWebChatMessage */ OpenaiWebChatMessage: { @@ -1126,7 +1152,7 @@ export interface components { /** Children */ children: (string)[]; /** Content */ - content?: components["schemas"]["OpenaiWebChatMessageTextContent"] | components["schemas"]["OpenaiWebChatMessageCodeContent"] | components["schemas"]["OpenaiWebChatMessageExecutionOutputContent"] | components["schemas"]["OpenaiWebChatMessageStderrContent"] | components["schemas"]["OpenaiWebChatMessageTetherBrowsingDisplayContent"] | components["schemas"]["OpenaiWebChatMessageTetherQuoteContent"] | components["schemas"]["OpenaiWebChatMessageSystemErrorContent"]; + content?: components["schemas"]["OpenaiWebChatMessageTextContent"] | components["schemas"]["OpenaiWebChatMessageMultimodalTextContent"] | components["schemas"]["OpenaiWebChatMessageCodeContent"] | components["schemas"]["OpenaiWebChatMessageExecutionOutputContent"] | components["schemas"]["OpenaiWebChatMessageStderrContent"] | components["schemas"]["OpenaiWebChatMessageTetherBrowsingDisplayContent"] | components["schemas"]["OpenaiWebChatMessageTetherQuoteContent"] | components["schemas"]["OpenaiWebChatMessageSystemErrorContent"]; /** Metadata */ metadata?: components["schemas"]["OpenaiWebChatMessageMetadata"] | components["schemas"]["OpenaiApiChatMessageMetadata"]; }; @@ -1269,6 +1295,27 @@ export interface components { /** Type */ type?: string; }; + /** OpenaiWebChatMessageMultimodalTextContent */ + OpenaiWebChatMessageMultimodalTextContent: { + /** + * Content Type + * @enum {string} + */ + content_type: "multimodal_text"; + /** Parts */ + parts?: (string | components["schemas"]["OpenaiWebChatMessageMultimodalTextContentImagePart"] | Record)[]; + }; + /** OpenaiWebChatMessageMultimodalTextContentImagePart */ + OpenaiWebChatMessageMultimodalTextContentImagePart: { + /** Asset Pointer */ + asset_pointer?: string; + /** Size Bytes */ + size_bytes?: number; + /** Width */ + width?: number; + /** Height */ + height?: number; + }; /** OpenaiWebChatMessageStderrContent */ OpenaiWebChatMessageStderrContent: { /** @@ -1475,6 +1522,10 @@ export interface components { daily_available_time_slots: (components["schemas"]["DailyTimeSlot"])[]; available_models: (components["schemas"]["OpenaiWebChatModels"])[]; per_model_ask_count: components["schemas"]["OpenaiWebPerModelAskCount"]; + /** Allow Uploading Attachments */ + allow_uploading_attachments: boolean; + /** Allow Uploading Multimodal Images */ + allow_uploading_multimodal_images: boolean; }; /** RequestLogAggregation */ RequestLogAggregation: { @@ -1577,6 +1628,8 @@ export interface components { UploadedFileOpenaiWebInfo: { /** File Id */ file_id?: string; + /** Use Case */ + use_case?: ("ace_upload" | "multimodal") | string; /** * Upload Url * @description 上传文件的url, 上传后应清空该字段 @@ -2199,28 +2252,6 @@ export interface operations { }; }; }; - get_file_download_url_conv_files__file_id__download_url_get: { - /** Get File Download Url */ - parameters: { - path: { - file_id: string; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": string; - }; - }; - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; get_conversation_interpreter_download_url_conv__conversation_id__interpreter_download_url_get: { /** Get Conversation Interpreter Download Url */ parameters: { @@ -2511,6 +2542,31 @@ export interface operations { }; }; }; + get_file_download_url_files__file_id__download_url_get: { + /** + * Get File Download Url + * @description file_id: OpenAI 分配的 id,以 file- 开头 + */ + parameters: { + path: { + file_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": string; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; upload_file_to_local_files_local_upload_post: { /** * Upload File To Local diff --git a/frontend/src/types/schema.ts b/frontend/src/types/schema.ts index 12dc035e..65bed251 100644 --- a/frontend/src/types/schema.ts +++ b/frontend/src/types/schema.ts @@ -22,6 +22,7 @@ export type OpenaiWebChatMessageMetadata = components['schemas']['OpenaiWebChatM export type OpenaiApiChatMessageMetadata = components['schemas']['OpenaiApiChatMessageMetadata']; export type OpenaiWebChatMessageMetadataAttachment = components['schemas']['OpenaiWebChatMessageMetadataAttachment']; export type OpenaiWebChatMessageTextContent = components['schemas']['OpenaiWebChatMessageTextContent']; +export type OpenaiWebChatMessageMultimodalTextContent = components['schemas']['OpenaiWebChatMessageMultimodalTextContent']; export type OpenaiWebChatMessageCodeContent = components['schemas']['OpenaiWebChatMessageCodeContent']; export type OpenaiWebChatMessageExecutionOutputContent = components['schemas']['OpenaiWebChatMessageExecutionOutputContent']; export type OpenaiWebChatMessageStderrContent = components['schemas']['OpenaiWebChatMessageStderrContent']; @@ -30,6 +31,8 @@ export type OpenaiWebChatMessageMetadataCiteData = components['schemas']['Openai export type OpenaiWebChatMessageTetherQuoteContent = components['schemas']['OpenaiWebChatMessageTetherQuoteContent']; export type OpenaiWebChatMessageSystemErrorContent = components['schemas']['OpenaiWebChatMessageSystemErrorContent']; export type OpenaiApiChatMessageTextContent = components['schemas']['OpenaiApiChatMessageTextContent']; +export type OpenaiWebChatMessageMultimodalTextContentImagePart = components['schemas']['OpenaiWebChatMessageMultimodalTextContentImagePart']; + export type BaseChatMessage = components['schemas']['BaseChatMessage']; export type OpenaiApiChatMessage = components['schemas']['OpenaiApiChatMessage']; export type OpenaiWebChatMessage = components['schemas']['OpenaiWebChatMessage']; diff --git a/frontend/src/utils/chat.ts b/frontend/src/utils/chat.ts index e6dd2e31..0d74f070 100644 --- a/frontend/src/utils/chat.ts +++ b/frontend/src/utils/chat.ts @@ -7,6 +7,8 @@ import { OpenaiApiChatModels, OpenaiWebChatMessageCodeContent, OpenaiWebChatMessageMetadata, + OpenaiWebChatMessageMultimodalTextContent, + OpenaiWebChatMessageMultimodalTextContentImagePart, OpenaiWebChatMessageStderrContent, OpenaiWebChatMessageSystemErrorContent, OpenaiWebChatMessageTetherBrowsingDisplayContent, @@ -24,7 +26,7 @@ export const chatModelColorMap: Record = { gpt_4_mobile: 'darkpurple', gpt_4_browsing: 'purple', gpt_4_plugins: 'purple', - gpt_4_code_interpreter: 'darkblue' + gpt_4_code_interpreter: 'purple' }; export const getChatModelColor = (model_name: OpenaiWebChatModels | OpenaiApiChatModels | string | null) => { @@ -35,6 +37,7 @@ export const getChatModelColor = (model_name: OpenaiWebChatModels | OpenaiApiCha export const getChatModelIconStyle = (model_name: OpenaiWebChatModels | OpenaiApiChatModels | string | null) => { if (model_name == 'gpt_4_plugins') return 'plugins'; else if (model_name == 'gpt_4_browsing') return 'browsing'; + else if (model_name == 'gpt_4_code_interpreter') return 'code-interpreter'; else return 'default'; }; @@ -76,11 +79,30 @@ export const getContentRawText = (message: BaseChatMessage | null): string => { } else if (message.content.content_type == 'system_error') { const content = message.content as OpenaiWebChatMessageSystemErrorContent; return `${content.name}: ${content.text}`; - } else { + } else if (message.content.content_type == 'multimodal_text') { + const content = message.content as OpenaiWebChatMessageMultimodalTextContent; + for (const part of content.parts!) { + if (typeof part == 'string') return part; + } + return ''; + } + else { return `${message.content}`; } }; +export const getMultimodalContentImageParts = (message: BaseChatMessage | null): OpenaiWebChatMessageMultimodalTextContentImagePart[] => { + if (!message || !message.content) return []; + if (typeof message.content == 'string') return []; + if (message.content.content_type == 'multimodal_text') { + const content = message.content as OpenaiWebChatMessageMultimodalTextContent; + return content.parts!.filter((part) => { + return typeof part !== 'string'; + }) as OpenaiWebChatMessageMultimodalTextContentImagePart[]; + } + return []; +}; + export function getMessageListFromHistory( convHistory: BaseConversationHistory | undefined | null, lastNode: string | null = null diff --git a/frontend/src/views/admin/pages/conversation_manager.vue b/frontend/src/views/admin/pages/conversation_manager.vue index 3e4e43ed..7b780bf2 100644 --- a/frontend/src/views/admin/pages/conversation_manager.vue +++ b/frontend/src/views/admin/pages/conversation_manager.vue @@ -98,7 +98,6 @@ const checkedRowKeys = ref>([]); const refreshData = () => { getAdminAllConversationsApi(false).then((res) => { data.value = res.data; - Message.success(t('tips.refreshed')); }); }; diff --git a/frontend/src/views/conversation/components/FileUploadRegion.vue b/frontend/src/views/conversation/components/FileUploadRegion.vue index 97c9d209..241656ab 100644 --- a/frontend/src/views/conversation/components/FileUploadRegion.vue +++ b/frontend/src/views/conversation/components/FileUploadRegion.vue @@ -1,14 +1,11 @@ diff --git a/frontend/src/views/conversation/components/InputRegion.vue b/frontend/src/views/conversation/components/InputRegion.vue index c7d3ca18..a848401c 100644 --- a/frontend/src/views/conversation/components/InputRegion.vue +++ b/frontend/src/views/conversation/components/InputRegion.vue @@ -80,13 +80,21 @@
- - + + + + + + + +
- +
diff --git a/frontend/src/views/conversation/components/MessageRowMultimodalTextDisplay.vue b/frontend/src/views/conversation/components/MessageRowMultimodalTextDisplay.vue new file mode 100644 index 00000000..6a8e1a42 --- /dev/null +++ b/frontend/src/views/conversation/components/MessageRowMultimodalTextDisplay.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/frontend/src/views/conversation/components/MessageRowTextDisplay.vue b/frontend/src/views/conversation/components/MessageRowTextDisplay.vue index a8c697f3..2994cbc8 100644 --- a/frontend/src/views/conversation/components/MessageRowTextDisplay.vue +++ b/frontend/src/views/conversation/components/MessageRowTextDisplay.vue @@ -9,14 +9,13 @@ import { computed, onMounted, ref } from 'vue'; import { useI18n } from 'vue-i18n'; -import { getInterpreterSandboxFileDownloadUrlApi } from '@/api/conv'; import { useAppStore } from '@/store'; -import { BaseChatMessage, OpenaiWebChatMessageMetadataCiteData } from '@/types/schema'; +import { BaseChatMessage } from '@/types/schema'; import { getTextMessageContent } from '@/utils/chat'; import md from '@/utils/markdown'; -import { Dialog } from '@/utils/tips'; import { bindOnclick, processPreTags } from '../utils/codeblock'; +import { processCitations, processSandboxLinks } from '../utils/message'; const appStore = useAppStore(); const contentRef = ref(); @@ -40,96 +39,6 @@ const renderedContent = computed(() => { return processPreTags(result, appStore.preference.codeAutoWrap); }); -function htmlToElement(html: string) { - var template = document.createElement('template'); - template.innerHTML = html.trim(); - return template.content.firstChild; -} - -function processCitations() { - const citationEls = contentRef.value!.querySelectorAll('span.browsing-citation'); - const citationUrls = [] as string[]; - citationEls.forEach((el) => { - let metadata = JSON.parse( - decodeURIComponent(el.getAttribute('data-citation') || '') - ) as OpenaiWebChatMessageMetadataCiteData; - if (!metadata) return; - let citationIndex = 0; - if (citationUrls.includes(metadata.url!)) { - citationIndex = citationUrls.indexOf(metadata.url!) + 1; - } else { - citationUrls.push(metadata.url!); - citationIndex = citationUrls.length; - } - const newEl = htmlToElement( - `${citationIndex}` - ); - if (newEl) el.replaceWith(newEl); - }); -} - -function processSandboxLinks() { - const sandboxLinks = contentRef.value!.querySelectorAll('a[href^="sandbox:"]'); - - sandboxLinks.forEach((link) => { - link.classList.add('sandbox'); - const hrefValue = link.getAttribute('href'); - const path = hrefValue?.replace('sandbox:', ''); - link.setAttribute('data-path', path || ''); - link.addEventListener('click', handleSandboxLinkClick); - }); -} - -function findMessageIdOfSandboxFile(sandboxPath: string) { - const messages = props.messages; - for (let i = 0; i < messages.length; i++) { - const message = messages[i]; - const content = getTextMessageContent([message]); - console.log(`search ${sandboxPath} in ${content}`); - if (content.includes(sandboxPath)) { - return message.id; - } - } - return null; -} - -function handleSandboxLinkClick(event: Event) { - const target = event.target as HTMLElement; - - if (target && target.matches('a.sandbox')) { - event.preventDefault(); - - // 设置元素禁止点击 - target.style.pointerEvents = 'none'; - - const path = target.getAttribute('data-path'); - const messageId = findMessageIdOfSandboxFile(path!); - if (!path) return; - if (!messageId) return; - - getInterpreterSandboxFileDownloadUrlApi(props.conversationId, messageId, path) - .then((response) => { - const url = response.data; - window.open(url, '_blank'); - }) - .catch((e) => { - console.error(e); - if (e.message == 'errors.resourceNotFound') { - Dialog.warning({ - content: t('tips.sandboxFileNotFound', [path]), - }); - } else { - Dialog.error({ - title: 'Error', - content: t('tips.sandboxFileDownloadError'), - }); - } - }).finally(() => { - target.style.pointerEvents = 'auto'; - }); - } -} - let observer = null; onMounted(() => { if (!contentRef.value) return; @@ -138,14 +47,16 @@ onMounted(() => { for (const mutation of mutations) { if (mutation.type === 'childList') { bindOnclick(contentRef); + processCitations(contentRef.value!); + processSandboxLinks(contentRef.value!, props.conversationId, props.messages); } } - processCitations(); }; + observer = new MutationObserver(callback); observer.observe(contentRef.value, { subtree: true, childList: true }); bindOnclick(contentRef); - processCitations(); - processSandboxLinks(); + processCitations(contentRef.value!); + processSandboxLinks(contentRef.value!, props.conversationId, props.messages); }); diff --git a/frontend/src/views/conversation/components/NewConversationForm.vue b/frontend/src/views/conversation/components/NewConversationForm.vue index 02a3f9e2..807d2c5b 100644 --- a/frontend/src/views/conversation/components/NewConversationForm.vue +++ b/frontend/src/views/conversation/components/NewConversationForm.vue @@ -2,7 +2,10 @@
- + @@ -36,7 +39,7 @@ import { computed, h, ref, watch } from 'vue'; import { getAllOpenaiChatPluginsApi, getInstalledOpenaiChatPluginsApi } from '@/api/chat'; import { i18n } from '@/i18n'; -import { useUserStore } from '@/store'; +import { useAppStore, useUserStore } from '@/store'; import { NewConversationInfo } from '@/types/custom'; import { OpenaiChatPlugin } from '@/types/schema'; import { Message } from '@/utils/tips'; @@ -46,6 +49,7 @@ import NewConversationFormSelectionPluginLabel from './NewConversationFormSelect const t = i18n.global.t as any; const userStore = useUserStore(); +const appStore = useAppStore(); const emits = defineEmits<{ (e: 'input', newConversationInfo: NewConversationInfo): void; @@ -69,13 +73,6 @@ const availableChatSourceTypes = computed(() => { ]; }); -const newConversationInfo = ref({ - title: null, - source: availableChatSourceTypes.value.length > 0 ? (availableChatSourceTypes.value[0].value as string) : null, - model: null, - openaiWebPlugins: null, -}); - const availableModels = computed(() => { if (!userStore.user) { return []; @@ -93,6 +90,13 @@ const availableModels = computed(() => { } }); +const newConversationInfo = ref({ + title: null, + source: null, + model: null, + openaiWebPlugins: null, +}); + const availablePlugins = ref(null); const loadingPlugins = ref(false); @@ -149,6 +153,34 @@ const renderPluginSelectionTag: SelectRenderTag = ({ option, handleClose }) => { ); }; +function setDefaultValues() { + // const defaultSource = computed(() => { + if (appStore.lastSelectedSource) { + if (availableChatSourceTypes.value.find((source) => source.value === appStore.lastSelectedSource)) { + newConversationInfo.value.source = appStore.lastSelectedSource; + } + } else { + newConversationInfo.value.source = + availableChatSourceTypes.value.length > 0 ? (availableChatSourceTypes.value[0].value as string) : null; + } + + if (appStore.lastSelectedModel) { + if ( + newConversationInfo.value.source === 'openai_web' && + availableModels.value.find((model) => model.value === appStore.lastSelectedModel) + ) { + newConversationInfo.value.model = appStore.lastSelectedModel; + } else if ( + newConversationInfo.value.source === 'openai_api' && + availableModels.value.find((model) => model.value === appStore.lastSelectedModel) + ) { + newConversationInfo.value.model = appStore.lastSelectedModel; + } + } +} + +setDefaultValues(); + watch( () => { return [newConversationInfo.value.source, newConversationInfo.value.model]; diff --git a/frontend/src/views/conversation/index.vue b/frontend/src/views/conversation/index.vue index a18a80ff..be918506 100644 --- a/frontend/src/views/conversation/index.vue +++ b/frontend/src/views/conversation/index.vue @@ -76,12 +76,12 @@ import { ArrowDown, ChatboxEllipses } from '@vicons/ionicons5'; -import { RemovableRef, useStorage } from '@vueuse/core'; +import { useStorage } from '@vueuse/core'; import { NButton, NIcon, useThemeVars } from 'naive-ui'; import { computed, ref, watch } from 'vue'; import { useI18n } from 'vue-i18n'; import { getAskWebsocketApiUrl } from '@/api/chat'; -import { useAppStore, useConversationStore, useUserStore } from '@/store'; +import { generateConversationTitleApi } from '@/api/conv'; +import { useAppStore, useConversationStore, useFileStore, useUserStore } from '@/store'; import { newConversationId } from '@/store/modules/conversation'; import { NewConversationInfo } from '@/types/custom'; import { @@ -112,7 +113,9 @@ import { BaseConversationHistory, BaseConversationSchema, OpenaiWebAskAttachment, - UploadedFileInfoSchema, + OpenaiWebChatMessageMetadata, + OpenaiWebChatMessageMultimodalTextContent, + OpenaiWebChatMessageMultimodalTextContentImagePart, } from '@/types/schema'; import { screenWidthGreaterThan } from '@/utils/media'; import { popupNewConversationDialog } from '@/utils/renders'; @@ -134,6 +137,7 @@ const rootRef = ref(); const historyRef = ref(); const userStore = useUserStore(); const appStore = useAppStore(); +const fileStore = useFileStore(); const conversationStore = useConversationStore(); const loadingAsk = ref(false); @@ -153,8 +157,7 @@ const isCurrentNewConversation = computed(() => { return currentConversationId.value?.startsWith('new_conversation') || false; }); const currentConversation = computed(() => { - if (isCurrentNewConversation.value) - return conversationStore.newConversation; + if (isCurrentNewConversation.value) return conversationStore.newConversation; const conv = conversationStore.conversations?.find((conversation: BaseConversationSchema) => { return conversation.conversation_id == currentConversationId.value; }); @@ -169,9 +172,28 @@ const inputValue = ref(''); const currentSendMessage = ref(null); const currentRecvMessages = ref([]); -const uploadedFileInfos = ref([]); -const isFileUploadAvailable = computed(() => { - return currentConversation.value?.source === 'openai_web' && currentConversation.value.current_model == 'gpt_4_code_interpreter'; +// const isFileUploadAvailable = computed(() => { +// return ( +// currentConversation.value?.source === 'openai_web' && +// currentConversation.value.current_model == 'gpt_4_code_interpreter' +// ); +// }); +const uploadMode = computed(() => { + const allowAttachmentsUploading = userStore.userInfo?.setting.openai_web.allow_uploading_attachments; + const allowMultimodalImagesUploading = userStore.userInfo?.setting.openai_web.allow_uploading_multimodal_images; + if ( + allowAttachmentsUploading && + currentConversation.value?.source === 'openai_web' && + currentConversation.value.current_model == 'gpt_4_code_interpreter' + ) + return 'attachments'; + else if ( + allowMultimodalImagesUploading && + currentConversation.value?.source === 'openai_web' && + currentConversation.value.current_model == 'gpt_4' + ) + return 'images'; + else return null; }); // 实际的 currentMessageList,加上当前正在发送的消息 @@ -224,12 +246,15 @@ const sendDisabled = computed(() => { const makeNewConversation = () => { if (hasNewConversation.value) return; popupNewConversationDialog(async (newConversationInfo: NewConversationInfo) => { - console.log('makeNewConversation', newConversationInfo); if (!newConversationInfo.source || !newConversationInfo.model) return; - newConversationInfo.title = newConversationInfo.title || `New Chat (${t('sources_short.' + newConversationInfo.source)})`; + if (newConversationInfo.source == 'openai_api') + newConversationInfo.title = newConversationInfo.title || `New Chat (${t('models.' + newConversationInfo.model)})`; + console.log('makeNewConversation', newConversationInfo); conversationStore.createNewConversation(newConversationInfo); currentConversationId.value = conversationStore.newConversation!.conversation_id!; hasNewConversation.value = true; + appStore.lastSelectedSource = newConversationInfo.source; + appStore.lastSelectedModel = newConversationInfo.model; }); }; @@ -256,17 +281,36 @@ const scrollToBottomSmooth = () => { }); }; -function buildTemporaryMessage(role: string, content: string, parent: string | undefined, model: string | undefined) { +function buildTemporaryMessage( + role: string, + text_content: string, + parent: string | undefined, + model: string | undefined, + openaiWebAttachments: OpenaiWebAskAttachment[] | null = null, + openaiWebMultimodalImageParts: OpenaiWebChatMessageMultimodalTextContentImagePart[] | null = null +) { const random_strid = Math.random().toString(36).substring(2, 16); - return { + const result = { id: `temp_${random_strid}`, source: currentConversation.value!.source, - content, + content: text_content, role: role, parent, // 其实没有用到parent children: [], - model - }; + model, + } as BaseChatMessage; + if (openaiWebAttachments) { + const metadata = { + attachments: openaiWebAttachments, + } as OpenaiWebChatMessageMetadata; + result.metadata = metadata; + } + if (openaiWebMultimodalImageParts) { + result.content = { + parts: [...openaiWebMultimodalImageParts, text_content], + } as OpenaiWebChatMessageMultimodalTextContent; + } + return result; } const sendMsg = async () => { @@ -285,27 +329,51 @@ const sendMsg = async () => { isAborted.value = false; let hasGotReply = false; - let attachments = [] as OpenaiWebAskAttachment[]; - if (isFileUploadAvailable.value && uploadedFileInfos.value.length > 0) { - attachments = uploadedFileInfos.value.filter((info) => info.openai_web_info && info.openai_web_info.file_id).map((info) => { - return { - id: info.openai_web_info!.file_id!, - name: info.original_filename, - size: info.size, - }; - }); + // 处理附件 + let attachments = null; + if (uploadMode.value === 'attachments' && fileStore.attachments.uploadedFileInfos.length > 0) { + attachments = fileStore.attachments.uploadedFileInfos + .filter((info) => info.openai_web_info && info.openai_web_info.file_id) + .map((info) => { + return { + id: info.openai_web_info!.file_id!, + name: info.original_filename, + size: info.size, + }; + }); + } + + // 处理 gpt-4 图片 + let multimodalImages = null; + if (uploadMode.value === 'images' && fileStore.images.uploadedFileInfos.length > 0) { + multimodalImages = fileStore.images.uploadedFileInfos + .filter((info) => info.openai_web_info && info.openai_web_info.file_id) + .map((info) => { + const fileId = info.openai_web_info!.file_id!; + const { width, height } = fileStore.images.imageMetadataMap[info.id] || {}; + return { + asset_pointer: `file-service://${fileId}`, + width, + height, + size_bytes: info.size, + } as OpenaiWebChatMessageMultimodalTextContentImagePart; + }); } const askRequest: AskRequest = { source: currentConversation.value!.source, new_conversation: isCurrentNewConversation.value, model: currentConversation.value!.current_model!, - content: text, - openai_web_plugin_ids: currentConvHistory.value!.metadata?.source === 'openai_web' ? currentConvHistory.value!.metadata?.plugin_ids : undefined, - openai_web_attachments: attachments || null, + text_content: text, + openai_web_plugin_ids: + currentConvHistory.value!.metadata?.source === 'openai_web' + ? currentConvHistory.value!.metadata?.plugin_ids + : undefined, + openai_web_attachments: attachments || undefined, + openai_web_multimodal_image_parts: multimodalImages || undefined, }; if (conversationStore.newConversation) { - askRequest.new_title = conversationStore.newConversation.title; + askRequest.new_title = conversationStore.newConversation.title || ''; // 这里可能为空串,表示需要生成标题 } else { askRequest.conversation_id = currentConversationId.value!; askRequest.parent = currentConvHistory.value.current_node; @@ -315,10 +383,18 @@ const sendMsg = async () => { if (text == ':continue') { currentSendMessage.value = null; currentRecvMessages.value = []; - } - else { - currentSendMessage.value = buildTemporaryMessage('user', text, currentConvHistory.value?.current_node, currentConversation.value!.current_model!); - currentRecvMessages.value = [buildTemporaryMessage('assistant', '...', currentSendMessage.value.id, currentConversation.value!.current_model!)]; + } else { + currentSendMessage.value = buildTemporaryMessage( + 'user', + text, + currentConvHistory.value?.current_node, + currentConversation.value!.current_model!, + attachments, + multimodalImages + ); + currentRecvMessages.value = [ + buildTemporaryMessage('assistant', '...', currentSendMessage.value.id, currentConversation.value!.current_model!), + ]; } const wsUrl = getAskWebsocketApiUrl(); let hasError = false; @@ -349,7 +425,10 @@ const sendMsg = async () => { hasGotReply = true; } const message = response.message as BaseChatMessage; - if (message.role !== 'user') { + if (message.role == 'user') { + console.log('got message', message); + currentSendMessage.value = message; + } else { const index = currentRecvMessages.value.findIndex((msg) => msg.id === message.id); if (index === -1) { currentRecvMessages.value.push(message); @@ -364,6 +443,7 @@ const sendMsg = async () => { hasError = true; console.error('websocket received error message', response); wsErrorMessage = response; + // TODO Message error } if (autoScrolling.value) scrollToBottom(); }; @@ -378,13 +458,28 @@ const sendMsg = async () => { let allNewMessages = [] as BaseChatMessage[]; if (currentSendMessage.value) { allNewMessages = [currentSendMessage.value] as BaseChatMessage[]; - } for (const msg of currentRecvMessages.value) { allNewMessages.push(msg); } - if (currentConversationId.value == newConversationId) { + // 更新对话信息,恢复正常状态 + if (isCurrentNewConversation.value) { + // 尝试生成标题 + if ( + askRequest.source == 'openai_web' && + (askRequest.new_title == undefined || askRequest.new_title.length == 0) + ) { + const lastRecvMessageId = allNewMessages[allNewMessages.length - 1].id; + console.log('try to generate conversation title', respConversationId, lastRecvMessageId); + try { + const response = await generateConversationTitleApi(respConversationId!, lastRecvMessageId); + currentConvHistory.value!.title = response.data; + } catch (err) { + console.error('Failed to generate conversation title', err); + } + } + const newConvHistory = { _id: respConversationId!, source: 'openai_web', @@ -406,6 +501,10 @@ const sendMsg = async () => { currentSendMessage.value = null; currentRecvMessages.value = []; currentConversationId.value = respConversationId!; // 这里将会导致 currentConversation 切换 + + // 清除附件 + fileStore.clearAll(); + await conversationStore.fetchAllConversations(); conversationStore.removeNewConversation(); hasNewConversation.value = false; diff --git a/frontend/src/views/conversation/utils/message.ts b/frontend/src/views/conversation/utils/message.ts index a7558838..5bee9e6c 100644 --- a/frontend/src/views/conversation/utils/message.ts +++ b/frontend/src/views/conversation/utils/message.ts @@ -1,5 +1,10 @@ -import { BaseChatMessage } from '@/types/schema'; -import { getContentRawText } from '@/utils/chat'; +import { getFileDownloadUrlApi, getInterpreterSandboxFileDownloadUrlApi } from '@/api/conv'; +import { i18n } from '@/i18n'; +import { BaseChatMessage, OpenaiWebChatMessageMetadataCiteData } from '@/types/schema'; +import { getContentRawText, getTextMessageContent } from '@/utils/chat'; +import { Dialog } from '@/utils/tips'; + +const t = i18n.global.t as any; // DisplayItem 表示由几条消息合并而来的一条消息,例如前面是若干次插件调用/browse,最后是正常的文本 interface BaseDisplayItem { @@ -16,7 +21,7 @@ interface DisplayItemText extends BaseDisplayItem { interface DisplayItemPluginCall extends BaseDisplayItem { type: 'plugin_call'; requestContent: string | undefined; - recipient: string | undefined; // plugin_name.xxx + recipient: string | undefined; // plugin_name.xxx responseContent: string | undefined; } @@ -35,10 +40,120 @@ export function processDisplayItems(messages: BaseChatMessage[]) { currentItem.mergeCount += 1; } else { if (currentItem != null) result.push(currentItem); - currentItem = { type: 'text', finishTime: message.create_time, content: getContentRawText(message), mergeCount: 1 }; + currentItem = { + type: 'text', + finishTime: message.create_time, + content: getContentRawText(message), + mergeCount: 1, + }; } } } } return result; +} + +export function htmlToElement(html: string) { + const template = document.createElement('template'); + template.innerHTML = html.trim(); + return template.content.firstChild; +} + +export function processCitations(contentDiv: HTMLDivElement) { + const citationEls = contentDiv!.querySelectorAll('span.browsing-citation'); + const citationUrls = [] as string[]; + citationEls.forEach((el) => { + const metadata = JSON.parse( + decodeURIComponent(el.getAttribute('data-citation') || '') + ) as OpenaiWebChatMessageMetadataCiteData; + if (!metadata) return; + let citationIndex = 0; + if (citationUrls.includes(metadata.url!)) { + citationIndex = citationUrls.indexOf(metadata.url!) + 1; + } else { + citationUrls.push(metadata.url!); + citationIndex = citationUrls.length; + } + const newEl = htmlToElement( + `${citationIndex}` + ); + if (newEl) el.replaceWith(newEl); + }); +} + +function findMessageIdOfSandboxFile(sandboxPath: string, messages: BaseChatMessage[]) { + for (let i = 0; i < messages.length; i++) { + const message = messages[i]; + const content = getTextMessageContent([message]); + console.log(`search ${sandboxPath} in ${content}`); + if (content.includes(sandboxPath)) { + return message.id; + } + } + return null; +} + +function getSandboxLinkClickHandler(conversationId: string, messages: BaseChatMessage[]) { + return (event: Event) => { + const target = event.target as HTMLElement; + + if (target && target.matches('a.sandbox')) { + event.preventDefault(); + + // 设置元素禁止点击 + target.style.pointerEvents = 'none'; + + const path = target.getAttribute('data-path'); + const messageId = findMessageIdOfSandboxFile(path!, messages); + if (!path) return; + if (!messageId) return; + + getInterpreterSandboxFileDownloadUrlApi(conversationId, messageId, path) + .then((response) => { + const url = response.data; + window.open(url, '_blank'); + }) + .catch((e) => { + console.error(e); + if (e.message == 'errors.resourceNotFound') { + Dialog.warning({ + content: t('tips.sandboxFileNotFound', [path]), + }); + } else { + Dialog.error({ + title: 'Error', + content: t('tips.sandboxFileDownloadError'), + }); + } + }) + .finally(() => { + target.style.pointerEvents = 'auto'; + }); + } + }; +} + +export function processSandboxLinks(contentDiv: HTMLDivElement, conversationId: string, messages: BaseChatMessage[]) { + const sandboxLinks = contentDiv.querySelectorAll('a[href^="sandbox:"]'); + + sandboxLinks.forEach((link) => { + link.classList.add('sandbox'); + const hrefValue = link.getAttribute('href'); + const path = hrefValue?.replace('sandbox:', ''); + link.setAttribute('data-path', path || ''); + const clickHandler = getSandboxLinkClickHandler(conversationId, messages); + link.addEventListener('click', clickHandler); + }); +} + +export async function getImageDownloadUrlFromFileServiceSchemaUrl(url: string | undefined) { + if (!url || !url.startsWith('file-service://')) return null; + try { + const response = await getFileDownloadUrlApi(url.split('file-service://')[1]); + return response.data; + } + catch (e) { + console.error(e); + return null; + } } \ No newline at end of file