feat: Chat file metadata (#1133)
* chore: chat question metadata * chore: update * chore: update env * chore: update env
This commit is contained in:
parent
cd10010477
commit
5195dae3a5
|
|
@ -98,9 +98,10 @@ jobs:
|
||||||
sed -i 's|GOTRUE_RATE_LIMIT_EMAIL_SENT=100|GOTRUE_RATE_LIMIT_EMAIL_SENT=1000|' .env
|
sed -i 's|GOTRUE_RATE_LIMIT_EMAIL_SENT=100|GOTRUE_RATE_LIMIT_EMAIL_SENT=1000|' .env
|
||||||
sed -i 's|APPFLOWY_MAILER_SMTP_USERNAME=.*|APPFLOWY_MAILER_SMTP_USERNAME=${{ secrets.CI_GOTRUE_SMTP_USER }}|' .env
|
sed -i 's|APPFLOWY_MAILER_SMTP_USERNAME=.*|APPFLOWY_MAILER_SMTP_USERNAME=${{ secrets.CI_GOTRUE_SMTP_USER }}|' .env
|
||||||
sed -i 's|APPFLOWY_MAILER_SMTP_PASSWORD=.*|APPFLOWY_MAILER_SMTP_PASSWORD=${{ secrets.CI_GOTRUE_SMTP_PASS }}|' .env
|
sed -i 's|APPFLOWY_MAILER_SMTP_PASSWORD=.*|APPFLOWY_MAILER_SMTP_PASSWORD=${{ secrets.CI_GOTRUE_SMTP_PASS }}|' .env
|
||||||
sed -i 's|APPFLOWY_AI_OPENAI_API_KEY=.*|APPFLOWY_AI_OPENAI_API_KEY=${{ secrets.CI_OPENAI_API_KEY }}|' .env
|
sed -i 's|AI_OPENAI_API_KEY=.*|AI_OPENAI_API_KEY=${{ secrets.CI_OPENAI_API_KEY }}|' .env
|
||||||
sed -i "s|LOCAL_AI_AWS_ACCESS_KEY_ID=.*|LOCAL_AI_AWS_ACCESS_KEY_ID=${{ secrets.LOCAL_AI_AWS_ACCESS_KEY_ID }}|" .env
|
sed -i "s|AI_AWS_ACCESS_KEY_ID=.*|AI_AWS_ACCESS_KEY_ID=${{ secrets.LOCAL_AI_AWS_ACCESS_KEY_ID }}|" .env
|
||||||
sed -i "s|LOCAL_AI_AWS_SECRET_ACCESS_KEY=.*|LOCAL_AI_AWS_SECRET_ACCESS_KEY=${{ secrets.LOCAL_AI_AWS_SECRET_ACCESS_KEY }}|" .env
|
sed -i "s|AI_AWS_SECRET_ACCESS_KEY=.*|AI_AWS_SECRET_ACCESS_KEY=${{ secrets.LOCAL_AI_AWS_SECRET_ACCESS_KEY }}|" .env
|
||||||
|
sed -i 's|AI_APPFLOWY_HOST=.*|AI_APPFLOWY_HOST=http://localhost:8000|' .env
|
||||||
sed -i 's|APPFLOWY_WEB_URL=.*|APPFLOWY_WEB_URL=http://localhost:3000|' .env
|
sed -i 's|APPFLOWY_WEB_URL=.*|APPFLOWY_WEB_URL=http://localhost:3000|' .env
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
|
|
||||||
23
deploy.env
23
deploy.env
|
|
@ -19,6 +19,9 @@ REDIS_PORT=6379
|
||||||
MINIO_HOST=minio
|
MINIO_HOST=minio
|
||||||
MINIO_PORT=9000
|
MINIO_PORT=9000
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY=minioadmin
|
||||||
|
AWS_SECRET=minioadmin
|
||||||
|
|
||||||
# AppFlowy Cloud
|
# AppFlowy Cloud
|
||||||
## URL that connects to the gotrue docker container
|
## URL that connects to the gotrue docker container
|
||||||
APPFLOWY_GOTRUE_BASE_URL=http://gotrue:9999
|
APPFLOWY_GOTRUE_BASE_URL=http://gotrue:9999
|
||||||
|
|
@ -110,8 +113,8 @@ APPFLOWY_S3_CREATE_BUCKET=true
|
||||||
# Keep this as true if you are using other S3 compatible storage provider other than AWS.
|
# Keep this as true if you are using other S3 compatible storage provider other than AWS.
|
||||||
APPFLOWY_S3_USE_MINIO=true
|
APPFLOWY_S3_USE_MINIO=true
|
||||||
APPFLOWY_S3_MINIO_URL=http://${MINIO_HOST}:${MINIO_PORT} # change this if you are using a different address for minio
|
APPFLOWY_S3_MINIO_URL=http://${MINIO_HOST}:${MINIO_PORT} # change this if you are using a different address for minio
|
||||||
APPFLOWY_S3_ACCESS_KEY=minioadmin
|
APPFLOWY_S3_ACCESS_KEY=${AWS_ACCESS_KEY}
|
||||||
APPFLOWY_S3_SECRET_KEY=minioadmin
|
APPFLOWY_S3_SECRET_KEY=${AWS_SECRET}
|
||||||
APPFLOWY_S3_BUCKET=appflowy
|
APPFLOWY_S3_BUCKET=appflowy
|
||||||
#APPFLOWY_S3_REGION=us-east-1
|
#APPFLOWY_S3_REGION=us-east-1
|
||||||
|
|
||||||
|
|
@ -146,12 +149,16 @@ NGINX_PORT=80
|
||||||
NGINX_TLS_PORT=443
|
NGINX_TLS_PORT=443
|
||||||
|
|
||||||
# AppFlowy AI
|
# AppFlowy AI
|
||||||
APPFLOWY_AI_OPENAI_API_KEY=
|
AI_OPENAI_API_KEY=
|
||||||
APPFLOWY_AI_SERVER_PORT=5001
|
AI_SERVER_PORT=5001
|
||||||
APPFLOWY_AI_SERVER_HOST=ai
|
AI_SERVER_HOST=ai
|
||||||
APPFLOWY_AI_DATABASE_URL=postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
|
AI_DATABASE_URL=postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
|
||||||
APPFLOWY_AI_REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}
|
AI_REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}
|
||||||
APPFLOWY_LOCAL_AI_TEST_ENABLED=false
|
LOCAL_AI_TEST_ENABLED=false
|
||||||
|
AI_APPFLOWY_BUCKET_NAME=appflowy
|
||||||
|
AI_APPFLOWY_HOST=http://your-host
|
||||||
|
AI_AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY}
|
||||||
|
AI_AWS_SECRET_ACCESS_KEY=${AWS_SECRET}
|
||||||
|
|
||||||
# AppFlowy Indexer
|
# AppFlowy Indexer
|
||||||
APPFLOWY_INDEXER_ENABLED=true
|
APPFLOWY_INDEXER_ENABLED=true
|
||||||
|
|
|
||||||
24
dev.env
24
dev.env
|
|
@ -6,6 +6,10 @@ APPFLOWY_WEBSOCKET_MAILBOX_SIZE=6000
|
||||||
APPFLOWY_DATABASE_MAX_CONNECTIONS=40
|
APPFLOWY_DATABASE_MAX_CONNECTIONS=40
|
||||||
APPFLOWY_DOCUMENT_CONTENT_SPLIT_LEN=8000
|
APPFLOWY_DOCUMENT_CONTENT_SPLIT_LEN=8000
|
||||||
|
|
||||||
|
# AWS
|
||||||
|
AWS_ACCESS_KEY=minioadmin
|
||||||
|
AWS_SECRET=minioadmin
|
||||||
|
|
||||||
# This file is used to set the environment variables for local development
|
# This file is used to set the environment variables for local development
|
||||||
# Copy this file to .env and change the values as needed
|
# Copy this file to .env and change the values as needed
|
||||||
|
|
||||||
|
|
@ -83,8 +87,8 @@ GOTRUE_EXTERNAL_APPLE_REDIRECT_URI=http://localhost:9999/callback
|
||||||
APPFLOWY_S3_CREATE_BUCKET=true
|
APPFLOWY_S3_CREATE_BUCKET=true
|
||||||
APPFLOWY_S3_USE_MINIO=true
|
APPFLOWY_S3_USE_MINIO=true
|
||||||
APPFLOWY_S3_MINIO_URL=http://localhost:9000 # change this if you are using a different address for minio
|
APPFLOWY_S3_MINIO_URL=http://localhost:9000 # change this if you are using a different address for minio
|
||||||
APPFLOWY_S3_ACCESS_KEY=minioadmin
|
APPFLOWY_S3_ACCESS_KEY=${AWS_ACCESS_KEY}
|
||||||
APPFLOWY_S3_SECRET_KEY=minioadmin
|
APPFLOWY_S3_SECRET_KEY=${AWS_SECRET}
|
||||||
APPFLOWY_S3_BUCKET=appflowy
|
APPFLOWY_S3_BUCKET=appflowy
|
||||||
#APPFLOWY_S3_REGION=us-east-1
|
#APPFLOWY_S3_REGION=us-east-1
|
||||||
|
|
||||||
|
|
@ -113,12 +117,16 @@ GF_SECURITY_ADMIN_PASSWORD=password
|
||||||
CLOUDFLARE_TUNNEL_TOKEN=
|
CLOUDFLARE_TUNNEL_TOKEN=
|
||||||
|
|
||||||
# AppFlowy AI
|
# AppFlowy AI
|
||||||
APPFLOWY_AI_OPENAI_API_KEY=
|
AI_OPENAI_API_KEY=
|
||||||
APPFLOWY_AI_SERVER_PORT=5001
|
AI_SERVER_PORT=5001
|
||||||
APPFLOWY_AI_SERVER_HOST=localhost
|
AI_SERVER_HOST=localhost
|
||||||
APPFLOWY_AI_DATABASE_URL=postgresql+psycopg://postgres:password@localhost:5432/postgres
|
AI_DATABASE_URL=postgresql+psycopg://postgres:password@localhost:5432/postgres
|
||||||
APPFLOWY_AI_REDIS_URL=redis://redis:6379
|
AI_REDIS_URL=redis://redis:6379
|
||||||
APPFLOWY_LOCAL_AI_TEST_ENABLED=false
|
LOCAL_AI_TEST_ENABLED=false
|
||||||
|
AI_APPFLOWY_BUCKET_NAME=appflowy
|
||||||
|
AI_APPFLOWY_HOST=http://localhost:8000
|
||||||
|
AI_AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY}
|
||||||
|
AI_AWS_SECRET_ACCESS_KEY=${AWS_SECRET}
|
||||||
|
|
||||||
# AppFlowy Indexer
|
# AppFlowy Indexer
|
||||||
APPFLOWY_INDEXER_ENABLED=true
|
APPFLOWY_INDEXER_ENABLED=true
|
||||||
|
|
|
||||||
|
|
@ -131,15 +131,15 @@ services:
|
||||||
- APPFLOWY_ACCESS_CONTROL=${APPFLOWY_ACCESS_CONTROL}
|
- APPFLOWY_ACCESS_CONTROL=${APPFLOWY_ACCESS_CONTROL}
|
||||||
# For the CI testing, we set the database connection to 20. The default value is 40.
|
# For the CI testing, we set the database connection to 20. The default value is 40.
|
||||||
- APPFLOWY_DATABASE_MAX_CONNECTIONS=20
|
- APPFLOWY_DATABASE_MAX_CONNECTIONS=20
|
||||||
- APPFLOWY_AI_SERVER_HOST=${APPFLOWY_AI_SERVER_HOST}
|
- AI_SERVER_HOST=${AI_SERVER_HOST}
|
||||||
- APPFLOWY_AI_SERVER_PORT=${APPFLOWY_AI_SERVER_PORT}
|
- AI_SERVER_PORT=${AI_SERVER_PORT}
|
||||||
- APPFLOWY_WEB_URL=${APPFLOWY_WEB_URL}
|
- APPFLOWY_WEB_URL=${APPFLOWY_WEB_URL}
|
||||||
- APPFLOWY_MAILER_SMTP_HOST=${APPFLOWY_MAILER_SMTP_HOST}
|
- APPFLOWY_MAILER_SMTP_HOST=${APPFLOWY_MAILER_SMTP_HOST}
|
||||||
- APPFLOWY_MAILER_SMTP_PORT=${APPFLOWY_MAILER_SMTP_PORT}
|
- APPFLOWY_MAILER_SMTP_PORT=${APPFLOWY_MAILER_SMTP_PORT}
|
||||||
- APPFLOWY_MAILER_SMTP_USERNAME=${APPFLOWY_MAILER_SMTP_USERNAME}
|
- APPFLOWY_MAILER_SMTP_USERNAME=${APPFLOWY_MAILER_SMTP_USERNAME}
|
||||||
- APPFLOWY_MAILER_SMTP_EMAIL=${APPFLOWY_MAILER_SMTP_EMAIL}
|
- APPFLOWY_MAILER_SMTP_EMAIL=${APPFLOWY_MAILER_SMTP_EMAIL}
|
||||||
- APPFLOWY_MAILER_SMTP_PASSWORD=${APPFLOWY_MAILER_SMTP_PASSWORD}
|
- APPFLOWY_MAILER_SMTP_PASSWORD=${APPFLOWY_MAILER_SMTP_PASSWORD}
|
||||||
- APPFLOWY_AI_OPENAI_API_KEY=${APPFLOWY_AI_OPENAI_API_KEY}
|
- AI_OPENAI_API_KEY=${AI_OPENAI_API_KEY}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
|
@ -171,12 +171,14 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "5001:5001"
|
- "5001:5001"
|
||||||
environment:
|
environment:
|
||||||
- OPENAI_API_KEY=${APPFLOWY_AI_OPENAI_API_KEY}
|
- OPENAI_API_KEY=${AI_OPENAI_API_KEY}
|
||||||
- LOCAL_AI_AWS_ACCESS_KEY_ID=${LOCAL_AI_AWS_ACCESS_KEY_ID}
|
- AI_AWS_ACCESS_KEY_ID=${AI_AWS_ACCESS_KEY_ID}
|
||||||
- LOCAL_AI_AWS_SECRET_ACCESS_KEY=${LOCAL_AI_AWS_SECRET_ACCESS_KEY}
|
- AI_AWS_SECRET_ACCESS_KEY=${AI_AWS_SECRET_ACCESS_KEY}
|
||||||
- APPFLOWY_AI_SERVER_PORT=${APPFLOWY_AI_SERVER_PORT}
|
- AI_SERVER_PORT=${AI_SERVER_PORT}
|
||||||
- APPFLOWY_AI_DATABASE_URL=${APPFLOWY_AI_DATABASE_URL}
|
- AI_DATABASE_URL=${AI_DATABASE_URL}
|
||||||
- APPFLOWY_AI_REDIS_URL=${APPFLOWY_AI_REDIS_URL}
|
- AI_REDIS_URL=${AI_REDIS_URL}
|
||||||
|
- AI_APPFLOWY_BUCKET_NAME=${AI_APPFLOWY_BUCKET_NAME}
|
||||||
|
- AI_APPFLOWY_HOST=${AI_APPFLOWY_HOST}
|
||||||
|
|
||||||
appflowy_worker:
|
appflowy_worker:
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
|
|
|
||||||
|
|
@ -133,11 +133,10 @@ services:
|
||||||
- APPFLOWY_MAILER_SMTP_TLS_KIND=${APPFLOWY_MAILER_SMTP_TLS_KIND}
|
- APPFLOWY_MAILER_SMTP_TLS_KIND=${APPFLOWY_MAILER_SMTP_TLS_KIND}
|
||||||
- APPFLOWY_ACCESS_CONTROL=${APPFLOWY_ACCESS_CONTROL}
|
- APPFLOWY_ACCESS_CONTROL=${APPFLOWY_ACCESS_CONTROL}
|
||||||
- APPFLOWY_DATABASE_MAX_CONNECTIONS=${APPFLOWY_DATABASE_MAX_CONNECTIONS}
|
- APPFLOWY_DATABASE_MAX_CONNECTIONS=${APPFLOWY_DATABASE_MAX_CONNECTIONS}
|
||||||
- APPFLOWY_AI_SERVER_HOST=${APPFLOWY_AI_SERVER_HOST}
|
- AI_SERVER_HOST=${AI_SERVER_HOST}
|
||||||
- APPFLOWY_AI_SERVER_PORT=${APPFLOWY_AI_SERVER_PORT}
|
- AI_SERVER_PORT=${AI_SERVER_PORT}
|
||||||
- APPFLOWY_AI_OPENAI_API_KEY=${APPFLOWY_AI_OPENAI_API_KEY}
|
- AI_OPENAI_API_KEY=${AI_OPENAI_API_KEY}
|
||||||
# Uncomment this line if AppFlowy Web has been deployed
|
# Uncomment this line if AppFlowy Web has been deployed
|
||||||
# - APPFLOWY_WEB_URL=${APPFLOWY_WEB_URL}
|
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
|
@ -161,10 +160,10 @@ services:
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
image: appflowyinc/appflowy_ai:${APPFLOWY_AI_VERSION:-latest}
|
image: appflowyinc/appflowy_ai:${APPFLOWY_AI_VERSION:-latest}
|
||||||
environment:
|
environment:
|
||||||
- OPENAI_API_KEY=${APPFLOWY_AI_OPENAI_API_KEY}
|
- OPENAI_API_KEY=${AI_OPENAI_API_KEY}
|
||||||
- APPFLOWY_AI_SERVER_PORT=${APPFLOWY_AI_SERVER_PORT}
|
- APPFLOWY_AI_SERVER_PORT=${AI_SERVER_PORT}
|
||||||
- APPFLOWY_AI_DATABASE_URL=${APPFLOWY_AI_DATABASE_URL}
|
- APPFLOWY_AI_DATABASE_URL=${AI_DATABASE_URL}
|
||||||
- APPFLOWY_AI_REDIS_URL=${APPFLOWY_AI_REDIS_URL}
|
- APPFLOWY_AI_REDIS_URL=${AI_REDIS_URL}
|
||||||
|
|
||||||
appflowy_worker:
|
appflowy_worker:
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::dto::{
|
use crate::dto::{
|
||||||
AIModel, CalculateSimilarityParams, ChatAnswer, ChatQuestion, CompleteTextResponse,
|
AIModel, CalculateSimilarityParams, ChatAnswer, ChatQuestion, CompleteTextResponse,
|
||||||
CompletionType, CreateChatContext, CustomPrompt, Document, LocalAIConfig, MessageData,
|
CompletionType, CreateChatContext, CustomPrompt, Document, LocalAIConfig, MessageData,
|
||||||
RepeatedLocalAIPackage, RepeatedRelatedQuestion, ResponseFormat, SearchDocumentsRequest,
|
QuestionMetadata, RepeatedLocalAIPackage, RepeatedRelatedQuestion, ResponseFormat,
|
||||||
SimilarityResponse, SummarizeRowResponse, TranslateRowData, TranslateRowResponse,
|
SearchDocumentsRequest, SimilarityResponse, SummarizeRowResponse, TranslateRowData,
|
||||||
|
TranslateRowResponse,
|
||||||
};
|
};
|
||||||
use crate::error::AIError;
|
use crate::error::AIError;
|
||||||
|
|
||||||
|
|
@ -173,6 +174,7 @@ impl AppFlowyAIClient {
|
||||||
|
|
||||||
pub async fn send_question(
|
pub async fn send_question(
|
||||||
&self,
|
&self,
|
||||||
|
workspace_id: &str,
|
||||||
chat_id: &str,
|
chat_id: &str,
|
||||||
question_id: i64,
|
question_id: i64,
|
||||||
content: &str,
|
content: &str,
|
||||||
|
|
@ -184,10 +186,13 @@ impl AppFlowyAIClient {
|
||||||
data: MessageData {
|
data: MessageData {
|
||||||
content: content.to_string(),
|
content: content.to_string(),
|
||||||
metadata,
|
metadata,
|
||||||
rag_ids: vec![],
|
|
||||||
message_id: Some(question_id.to_string()),
|
message_id: Some(question_id.to_string()),
|
||||||
},
|
},
|
||||||
format: Default::default(),
|
format: Default::default(),
|
||||||
|
metadata: QuestionMetadata {
|
||||||
|
workspace_id: workspace_id.to_string(),
|
||||||
|
rag_ids: vec![],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let url = format!("{}/chat/message", self.url);
|
let url = format!("{}/chat/message", self.url);
|
||||||
let resp = self
|
let resp = self
|
||||||
|
|
@ -203,6 +208,7 @@ impl AppFlowyAIClient {
|
||||||
|
|
||||||
pub async fn stream_question(
|
pub async fn stream_question(
|
||||||
&self,
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
chat_id: &str,
|
chat_id: &str,
|
||||||
content: &str,
|
content: &str,
|
||||||
metadata: Option<Value>,
|
metadata: Option<Value>,
|
||||||
|
|
@ -214,10 +220,13 @@ impl AppFlowyAIClient {
|
||||||
data: MessageData {
|
data: MessageData {
|
||||||
content: content.to_string(),
|
content: content.to_string(),
|
||||||
metadata,
|
metadata,
|
||||||
rag_ids,
|
|
||||||
message_id: None,
|
message_id: None,
|
||||||
},
|
},
|
||||||
format: Default::default(),
|
format: Default::default(),
|
||||||
|
metadata: QuestionMetadata {
|
||||||
|
workspace_id,
|
||||||
|
rag_ids,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let url = format!("{}/chat/message/stream", self.url);
|
let url = format!("{}/chat/message/stream", self.url);
|
||||||
let resp = self
|
let resp = self
|
||||||
|
|
@ -230,8 +239,10 @@ impl AppFlowyAIClient {
|
||||||
AIResponse::<()>::stream_response(resp).await
|
AIResponse::<()>::stream_response(resp).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn stream_question_v2(
|
pub async fn stream_question_v2(
|
||||||
&self,
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
chat_id: &str,
|
chat_id: &str,
|
||||||
question_id: i64,
|
question_id: i64,
|
||||||
content: &str,
|
content: &str,
|
||||||
|
|
@ -244,10 +255,13 @@ impl AppFlowyAIClient {
|
||||||
data: MessageData {
|
data: MessageData {
|
||||||
content: content.to_string(),
|
content: content.to_string(),
|
||||||
metadata,
|
metadata,
|
||||||
rag_ids,
|
|
||||||
message_id: Some(question_id.to_string()),
|
message_id: Some(question_id.to_string()),
|
||||||
},
|
},
|
||||||
format: ResponseFormat::default(),
|
format: ResponseFormat::default(),
|
||||||
|
metadata: QuestionMetadata {
|
||||||
|
workspace_id,
|
||||||
|
rag_ids,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
self.stream_question_v3(model, json).await
|
self.stream_question_v3(model, json).await
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,13 @@ pub struct ChatQuestion {
|
||||||
pub data: MessageData,
|
pub data: MessageData,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub format: ResponseFormat,
|
pub format: ResponseFormat,
|
||||||
|
pub metadata: QuestionMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct QuestionMetadata {
|
||||||
|
pub workspace_id: String,
|
||||||
|
pub rag_ids: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||||
|
|
@ -60,7 +67,7 @@ pub struct OutputContentMetadata {
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub custom_image_prompt: Option<String>,
|
pub custom_image_prompt: Option<String>,
|
||||||
|
|
||||||
/// The image model to use for generation (default: "dall-e-2").
|
/// The image model to use for generation (default: "dall-e-3").
|
||||||
#[serde(default = "default_image_model")]
|
#[serde(default = "default_image_model")]
|
||||||
pub image_model: String,
|
pub image_model: String,
|
||||||
|
|
||||||
|
|
@ -81,7 +88,7 @@ pub struct OutputContentMetadata {
|
||||||
|
|
||||||
// Default values for the fields
|
// Default values for the fields
|
||||||
fn default_image_model() -> String {
|
fn default_image_model() -> String {
|
||||||
"dall-e-2".to_string()
|
"dall-e-3".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_image_size() -> Option<String> {
|
fn default_image_size() -> Option<String> {
|
||||||
|
|
@ -98,8 +105,6 @@ pub struct MessageData {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub metadata: Option<serde_json::Value>,
|
pub metadata: Option<serde_json::Value>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub rag_ids: Vec<String>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub message_id: Option<String>,
|
pub message_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,14 @@ async fn create_chat_context_test() {
|
||||||
};
|
};
|
||||||
client.create_chat_text_context(context).await.unwrap();
|
client.create_chat_text_context(context).await.unwrap();
|
||||||
let resp = client
|
let resp = client
|
||||||
.send_question(&chat_id, 1, "Where I live?", &AIModel::GPT4oMini, None)
|
.send_question(
|
||||||
|
&uuid::Uuid::new_v4().to_string(),
|
||||||
|
&chat_id,
|
||||||
|
1,
|
||||||
|
"Where I live?",
|
||||||
|
&AIModel::GPT4oMini,
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// response will be something like:
|
// response will be something like:
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
use crate::appflowy_ai_client;
|
use crate::appflowy_ai_client;
|
||||||
|
|
||||||
use appflowy_ai_client::dto::{AIModel, STREAM_ANSWER_KEY};
|
use appflowy_ai_client::dto::AIModel;
|
||||||
use appflowy_ai_client::error::AIError;
|
|
||||||
use futures::stream::StreamExt;
|
|
||||||
use infra::reqwest::JsonStream;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn qa_test() {
|
async fn qa_test() {
|
||||||
|
|
@ -11,7 +8,14 @@ async fn qa_test() {
|
||||||
client.health_check().await.unwrap();
|
client.health_check().await.unwrap();
|
||||||
let chat_id = uuid::Uuid::new_v4().to_string();
|
let chat_id = uuid::Uuid::new_v4().to_string();
|
||||||
let resp = client
|
let resp = client
|
||||||
.send_question(&chat_id, 1, "I feel hungry", &AIModel::GPT4o, None)
|
.send_question(
|
||||||
|
&uuid::Uuid::new_v4().to_string(),
|
||||||
|
&chat_id,
|
||||||
|
1,
|
||||||
|
"I feel hungry",
|
||||||
|
&AIModel::GPT4o,
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(!resp.content.is_empty());
|
assert!(!resp.content.is_empty());
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ pub fn ai_test_enabled() -> bool {
|
||||||
load_env();
|
load_env();
|
||||||
|
|
||||||
// local ai test is disable by default
|
// local ai test is disable by default
|
||||||
let enabled = get_bool_from_env_var("APPFLOWY_LOCAL_AI_TEST_ENABLED");
|
let enabled = get_bool_from_env_var("LOCAL_AI_TEST_ENABLED");
|
||||||
if enabled {
|
if enabled {
|
||||||
trace!("Local AI test is enabled");
|
trace!("Local AI test is enabled");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ pub trait BucketClient {
|
||||||
pub trait BlobKey: Send + Sync {
|
pub trait BlobKey: Send + Sync {
|
||||||
fn workspace_id(&self) -> &Uuid;
|
fn workspace_id(&self) -> &Uuid;
|
||||||
fn object_key(&self) -> String;
|
fn object_key(&self) -> String;
|
||||||
fn meta_key(&self) -> String;
|
fn blob_metadata_key(&self) -> String;
|
||||||
fn e_tag(&self) -> &str;
|
fn e_tag(&self) -> &str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,11 +99,11 @@ where
|
||||||
file_type: String,
|
file_type: String,
|
||||||
file_size: usize,
|
file_size: usize,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
if is_blob_metadata_exists(&self.pg_pool, key.workspace_id(), &key.meta_key()).await? {
|
if is_blob_metadata_exists(&self.pg_pool, key.workspace_id(), &key.blob_metadata_key()).await? {
|
||||||
warn!(
|
warn!(
|
||||||
"file already exists, workspace_id: {}, meta_key: {}",
|
"file already exists, workspace_id: {}, blob_metadata_key: {}",
|
||||||
key.workspace_id(),
|
key.workspace_id(),
|
||||||
key.meta_key()
|
key.blob_metadata_key()
|
||||||
);
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +114,7 @@ where
|
||||||
.await?;
|
.await?;
|
||||||
insert_blob_metadata(
|
insert_blob_metadata(
|
||||||
&self.pg_pool,
|
&self.pg_pool,
|
||||||
&key.meta_key(),
|
&key.blob_metadata_key(),
|
||||||
key.workspace_id(),
|
key.workspace_id(),
|
||||||
&file_type,
|
&file_type,
|
||||||
file_size,
|
file_size,
|
||||||
|
|
@ -127,7 +127,7 @@ where
|
||||||
self.client.delete_blob(&key.object_key()).await?;
|
self.client.delete_blob(&key.object_key()).await?;
|
||||||
|
|
||||||
let mut tx = self.pg_pool.begin().await?;
|
let mut tx = self.pg_pool.begin().await?;
|
||||||
delete_blob_metadata(&mut tx, key.workspace_id(), &key.meta_key()).await?;
|
delete_blob_metadata(&mut tx, key.workspace_id(), &key.blob_metadata_key()).await?;
|
||||||
tx.commit().await?;
|
tx.commit().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -135,9 +135,9 @@ where
|
||||||
pub async fn get_blob_metadata(
|
pub async fn get_blob_metadata(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
meta_key: &str,
|
store_key: &str,
|
||||||
) -> Result<AFBlobMetadataRow, AppError> {
|
) -> Result<AFBlobMetadataRow, AppError> {
|
||||||
let metadata = get_blob_metadata(&self.pg_pool, workspace_id, meta_key).await?;
|
let metadata = get_blob_metadata(&self.pg_pool, workspace_id, store_key).await?;
|
||||||
Ok(metadata)
|
Ok(metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,7 +180,7 @@ where
|
||||||
self.client.complete_upload(&key.object_key(), req).await?;
|
self.client.complete_upload(&key.object_key(), req).await?;
|
||||||
insert_blob_metadata(
|
insert_blob_metadata(
|
||||||
&self.pg_pool,
|
&self.pg_pool,
|
||||||
&key.meta_key(),
|
&key.blob_metadata_key(),
|
||||||
key.workspace_id(),
|
key.workspace_id(),
|
||||||
&content_type,
|
&content_type,
|
||||||
content_length,
|
content_length,
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ pub async fn init_state(config: &Config, rt_cmd_tx: CLCommandSender) -> Result<A
|
||||||
enable: get_env_var("APPFLOWY_INDEXER_ENABLED", "true")
|
enable: get_env_var("APPFLOWY_INDEXER_ENABLED", "true")
|
||||||
.parse::<bool>()
|
.parse::<bool>()
|
||||||
.unwrap_or(true),
|
.unwrap_or(true),
|
||||||
openai_api_key: Secret::new(get_env_var("APPFLOWY_AI_OPENAI_API_KEY", "")),
|
openai_api_key: Secret::new(get_env_var("AI_OPENAI_API_KEY", "")),
|
||||||
embedding_buffer_size: get_env_var("APPFLOWY_INDEXER_EMBEDDING_BUFFER_SIZE", "2000")
|
embedding_buffer_size: get_env_var("APPFLOWY_INDEXER_EMBEDDING_BUFFER_SIZE", "2000")
|
||||||
.parse::<usize>()
|
.parse::<usize>()
|
||||||
.unwrap_or(2000),
|
.unwrap_or(2000),
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ pub fn get_configuration() -> Result<Config, anyhow::Error> {
|
||||||
redis_worker_count: get_env_var("APPFLOWY_REDIS_WORKERS", "60").parse()?,
|
redis_worker_count: get_env_var("APPFLOWY_REDIS_WORKERS", "60").parse()?,
|
||||||
ai: AISettings {
|
ai: AISettings {
|
||||||
port: get_env_var("APPFLOWY_AI_SERVER_PORT", "5001").parse()?,
|
port: get_env_var("APPFLOWY_AI_SERVER_PORT", "5001").parse()?,
|
||||||
host: get_env_var("APPFLOWY_AI_SERVER_HOST", "localhost"),
|
host: get_env_var("AI_SERVER_HOST", "localhost"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Ok(config)
|
Ok(config)
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ pub async fn create_app(listener: TcpListener, config: Config) -> Result<(), Err
|
||||||
.parse::<bool>()
|
.parse::<bool>()
|
||||||
.unwrap_or(true),
|
.unwrap_or(true),
|
||||||
open_api_key: Secret::new(appflowy_collaborate::config::get_env_var(
|
open_api_key: Secret::new(appflowy_collaborate::config::get_env_var(
|
||||||
"APPFLOWY_AI_OPENAI_API_KEY",
|
"AI_OPENAI_API_KEY",
|
||||||
"",
|
"",
|
||||||
)),
|
)),
|
||||||
tick_interval_secs: 10,
|
tick_interval_secs: 10,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ use serde::Deserialize;
|
||||||
use crate::api::util::ai_model_from_header;
|
use crate::api::util::ai_model_from_header;
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
use appflowy_ai_client::dto::{
|
use appflowy_ai_client::dto::{
|
||||||
ChatQuestion, ChatQuestionQuery, CreateChatContext, MessageData, RepeatedRelatedQuestion,
|
ChatQuestion, ChatQuestionQuery, CreateChatContext, MessageData, QuestionMetadata,
|
||||||
|
RepeatedRelatedQuestion,
|
||||||
};
|
};
|
||||||
use authentication::jwt::UserUuid;
|
use authentication::jwt::UserUuid;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
@ -88,7 +89,7 @@ pub fn chat_scope() -> Scope {
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{chat_id}/{message_id}/v2/answer/stream")
|
web::resource("/{chat_id}/{message_id}/v2/answer/stream")
|
||||||
.route(web::get().to(answer_stream_v2_handler))
|
.route(web::get().to(answer_stream_v2_handler)) // Deprecated since 0.9.2
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/{chat_id}/answer/stream")
|
web::resource("/{chat_id}/answer/stream")
|
||||||
|
|
@ -140,13 +141,22 @@ async fn create_chat_context_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_question_handler(
|
async fn update_question_handler(
|
||||||
|
path: web::Path<(String, String)>,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
payload: Json<UpdateChatMessageContentParams>,
|
payload: Json<UpdateChatMessageContentParams>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> actix_web::Result<JsonAppResponse<()>> {
|
) -> actix_web::Result<JsonAppResponse<()>> {
|
||||||
|
let (workspace_id, _chat_id) = path.into_inner();
|
||||||
let params = payload.into_inner();
|
let params = payload.into_inner();
|
||||||
let ai_model = ai_model_from_header(&req);
|
let ai_model = ai_model_from_header(&req);
|
||||||
update_chat_message(&state.pg_pool, params, state.ai_client.clone(), ai_model).await?;
|
update_chat_message(
|
||||||
|
workspace_id,
|
||||||
|
&state.pg_pool,
|
||||||
|
params,
|
||||||
|
state.ai_client.clone(),
|
||||||
|
ai_model,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(AppResponse::Ok().into())
|
Ok(AppResponse::Ok().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,9 +246,10 @@ async fn answer_handler(
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> actix_web::Result<JsonAppResponse<ChatMessage>> {
|
) -> actix_web::Result<JsonAppResponse<ChatMessage>> {
|
||||||
let (_workspace_id, chat_id, message_id) = path.into_inner();
|
let (workspace_id, chat_id, message_id) = path.into_inner();
|
||||||
let ai_model = ai_model_from_header(&req);
|
let ai_model = ai_model_from_header(&req);
|
||||||
let message = generate_chat_message_answer(
|
let message = generate_chat_message_answer(
|
||||||
|
workspace_id,
|
||||||
&state.pg_pool,
|
&state.pg_pool,
|
||||||
state.ai_client.clone(),
|
state.ai_client.clone(),
|
||||||
message_id,
|
message_id,
|
||||||
|
|
@ -255,14 +266,21 @@ async fn answer_stream_handler(
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> actix_web::Result<HttpResponse> {
|
) -> actix_web::Result<HttpResponse> {
|
||||||
let (_workspace_id, chat_id, question_id) = path.into_inner();
|
let (workspace_id, chat_id, question_id) = path.into_inner();
|
||||||
let (content, metadata) =
|
let (content, metadata) =
|
||||||
chat::chat_ops::select_chat_message_content(&state.pg_pool, question_id).await?;
|
chat::chat_ops::select_chat_message_content(&state.pg_pool, question_id).await?;
|
||||||
let rag_ids = chat::chat_ops::select_chat_rag_ids(&state.pg_pool, &chat_id).await?;
|
let rag_ids = chat::chat_ops::select_chat_rag_ids(&state.pg_pool, &chat_id).await?;
|
||||||
let ai_model = ai_model_from_header(&req);
|
let ai_model = ai_model_from_header(&req);
|
||||||
match state
|
match state
|
||||||
.ai_client
|
.ai_client
|
||||||
.stream_question(&chat_id, &content, Some(metadata), rag_ids, &ai_model)
|
.stream_question(
|
||||||
|
workspace_id,
|
||||||
|
&chat_id,
|
||||||
|
&content,
|
||||||
|
Some(metadata),
|
||||||
|
rag_ids,
|
||||||
|
&ai_model,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(answer_stream) => {
|
Ok(answer_stream) => {
|
||||||
|
|
@ -289,7 +307,7 @@ async fn answer_stream_v2_handler(
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> actix_web::Result<HttpResponse> {
|
) -> actix_web::Result<HttpResponse> {
|
||||||
let (_workspace_id, chat_id, question_id) = path.into_inner();
|
let (workspace_id, chat_id, question_id) = path.into_inner();
|
||||||
let (content, metadata) =
|
let (content, metadata) =
|
||||||
chat::chat_ops::select_chat_message_content(&state.pg_pool, question_id).await?;
|
chat::chat_ops::select_chat_message_content(&state.pg_pool, question_id).await?;
|
||||||
let rag_ids = chat::chat_ops::select_chat_rag_ids(&state.pg_pool, &chat_id).await?;
|
let rag_ids = chat::chat_ops::select_chat_rag_ids(&state.pg_pool, &chat_id).await?;
|
||||||
|
|
@ -304,6 +322,7 @@ async fn answer_stream_v2_handler(
|
||||||
match state
|
match state
|
||||||
.ai_client
|
.ai_client
|
||||||
.stream_question_v2(
|
.stream_question_v2(
|
||||||
|
workspace_id,
|
||||||
&chat_id,
|
&chat_id,
|
||||||
question_id,
|
question_id,
|
||||||
&content,
|
&content,
|
||||||
|
|
@ -333,10 +352,12 @@ async fn answer_stream_v2_handler(
|
||||||
|
|
||||||
#[instrument(level = "debug", skip_all, err)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
async fn answer_stream_v3_handler(
|
async fn answer_stream_v3_handler(
|
||||||
|
path: web::Path<(String, String)>,
|
||||||
payload: Json<ChatQuestionQuery>,
|
payload: Json<ChatQuestionQuery>,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> actix_web::Result<HttpResponse> {
|
) -> actix_web::Result<HttpResponse> {
|
||||||
|
let (workspace_id, _) = path.into_inner();
|
||||||
let payload = payload.into_inner();
|
let payload = payload.into_inner();
|
||||||
let (content, metadata) =
|
let (content, metadata) =
|
||||||
chat::chat_ops::select_chat_message_content(&state.pg_pool, payload.question_id).await?;
|
chat::chat_ops::select_chat_message_content(&state.pg_pool, payload.question_id).await?;
|
||||||
|
|
@ -348,10 +369,13 @@ async fn answer_stream_v3_handler(
|
||||||
data: MessageData {
|
data: MessageData {
|
||||||
content: content.to_string(),
|
content: content.to_string(),
|
||||||
metadata: Some(metadata),
|
metadata: Some(metadata),
|
||||||
rag_ids,
|
|
||||||
message_id: Some(payload.question_id.to_string()),
|
message_id: Some(payload.question_id.to_string()),
|
||||||
},
|
},
|
||||||
format: payload.format,
|
format: payload.format,
|
||||||
|
metadata: QuestionMetadata {
|
||||||
|
workspace_id,
|
||||||
|
rag_ids,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
trace!("[Chat] stream v3 {:?}", question);
|
trace!("[Chat] stream v3 {:?}", question);
|
||||||
match state
|
match state
|
||||||
|
|
|
||||||
|
|
@ -357,7 +357,7 @@ async fn get_blob_by_object_key(
|
||||||
// Get the metadata
|
// Get the metadata
|
||||||
let result = state
|
let result = state
|
||||||
.bucket_storage
|
.bucket_storage
|
||||||
.get_blob_metadata(key.workspace_id(), &key.meta_key())
|
.get_blob_metadata(key.workspace_id(), &key.blob_metadata_key())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Err(err) = result.as_ref() {
|
if let Err(err) = result.as_ref() {
|
||||||
|
|
@ -424,7 +424,7 @@ async fn get_blob_metadata_handler(
|
||||||
// Get the metadata
|
// Get the metadata
|
||||||
let metadata = state
|
let metadata = state
|
||||||
.bucket_storage
|
.bucket_storage
|
||||||
.get_blob_metadata(&path.workspace_id, &path.meta_key())
|
.get_blob_metadata(&path.workspace_id, &path.blob_metadata_key())
|
||||||
.await
|
.await
|
||||||
.map(|meta| BlobMetadata {
|
.map(|meta| BlobMetadata {
|
||||||
workspace_id: meta.workspace_id,
|
workspace_id: meta.workspace_id,
|
||||||
|
|
@ -448,7 +448,7 @@ async fn get_blob_metadata_v1_handler(
|
||||||
// Get the metadata
|
// Get the metadata
|
||||||
let metadata = state
|
let metadata = state
|
||||||
.bucket_storage
|
.bucket_storage
|
||||||
.get_blob_metadata(&path.workspace_id, &path.meta_key())
|
.get_blob_metadata(&path.workspace_id, &path.blob_metadata_key())
|
||||||
.await
|
.await
|
||||||
.map(|meta| BlobMetadata {
|
.map(|meta| BlobMetadata {
|
||||||
workspace_id: meta.workspace_id,
|
workspace_id: meta.workspace_id,
|
||||||
|
|
@ -589,7 +589,7 @@ impl BlobKey for BlobPathV0 {
|
||||||
format!("{}/{}", self.workspace_id, self.file_id)
|
format!("{}/{}", self.workspace_id, self.file_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn meta_key(&self) -> String {
|
fn blob_metadata_key(&self) -> String {
|
||||||
self.file_id.clone()
|
self.file_id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -615,7 +615,7 @@ impl BlobKey for BlobPathV1 {
|
||||||
format!("{}/{}/{}", self.workspace_id, self.parent_dir, self.file_id)
|
format!("{}/{}/{}", self.workspace_id, self.parent_dir, self.file_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn meta_key(&self) -> String {
|
fn blob_metadata_key(&self) -> String {
|
||||||
format!("{}_{}", self.parent_dir, self.file_id)
|
format!("{}_{}", self.parent_dir, self.file_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -332,7 +332,7 @@ pub async fn init_state(config: &Config, rt_cmd_tx: CLCommandSender) -> Result<A
|
||||||
enable: get_env_var("APPFLOWY_INDEXER_ENABLED", "true")
|
enable: get_env_var("APPFLOWY_INDEXER_ENABLED", "true")
|
||||||
.parse::<bool>()
|
.parse::<bool>()
|
||||||
.unwrap_or(true),
|
.unwrap_or(true),
|
||||||
openai_api_key: Secret::new(get_env_var("APPFLOWY_AI_OPENAI_API_KEY", "")),
|
openai_api_key: Secret::new(get_env_var("AI_OPENAI_API_KEY", "")),
|
||||||
embedding_buffer_size: appflowy_collaborate::config::get_env_var(
|
embedding_buffer_size: appflowy_collaborate::config::get_env_var(
|
||||||
"APPFLOWY_INDEXER_EMBEDDING_BUFFER_SIZE",
|
"APPFLOWY_INDEXER_EMBEDDING_BUFFER_SIZE",
|
||||||
"5000",
|
"5000",
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ pub(crate) async fn delete_chat(pg_pool: &PgPool, chat_id: &str) -> Result<(), A
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_chat_message(
|
pub async fn update_chat_message(
|
||||||
|
workspace_id: String,
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
params: UpdateChatMessageContentParams,
|
params: UpdateChatMessageContentParams,
|
||||||
ai_client: AppFlowyAIClient,
|
ai_client: AppFlowyAIClient,
|
||||||
|
|
@ -60,6 +61,7 @@ pub async fn update_chat_message(
|
||||||
// TODO(nathan): query the metadata from the database
|
// TODO(nathan): query the metadata from the database
|
||||||
let new_answer = ai_client
|
let new_answer = ai_client
|
||||||
.send_question(
|
.send_question(
|
||||||
|
&workspace_id,
|
||||||
¶ms.chat_id,
|
¶ms.chat_id,
|
||||||
params.message_id,
|
params.message_id,
|
||||||
¶ms.content,
|
¶ms.content,
|
||||||
|
|
@ -81,6 +83,7 @@ pub async fn update_chat_message(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn generate_chat_message_answer(
|
pub async fn generate_chat_message_answer(
|
||||||
|
workspace_id: String,
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
ai_client: AppFlowyAIClient,
|
ai_client: AppFlowyAIClient,
|
||||||
question_message_id: i64,
|
question_message_id: i64,
|
||||||
|
|
@ -91,6 +94,7 @@ pub async fn generate_chat_message_answer(
|
||||||
chat::chat_ops::select_chat_message_content(pg_pool, question_message_id).await?;
|
chat::chat_ops::select_chat_message_content(pg_pool, question_message_id).await?;
|
||||||
let new_answer = ai_client
|
let new_answer = ai_client
|
||||||
.send_question(
|
.send_question(
|
||||||
|
&workspace_id,
|
||||||
chat_id,
|
chat_id,
|
||||||
question_message_id,
|
question_message_id,
|
||||||
&content,
|
&content,
|
||||||
|
|
@ -145,6 +149,7 @@ pub async fn create_chat_message(
|
||||||
pub async fn create_chat_message_stream(
|
pub async fn create_chat_message_stream(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
uid: i64,
|
uid: i64,
|
||||||
|
workspace_id: String,
|
||||||
chat_id: String,
|
chat_id: String,
|
||||||
params: CreateChatMessageParams,
|
params: CreateChatMessageParams,
|
||||||
ai_client: AppFlowyAIClient,
|
ai_client: AppFlowyAIClient,
|
||||||
|
|
@ -186,7 +191,7 @@ pub async fn create_chat_message_stream(
|
||||||
match params.message_type {
|
match params.message_type {
|
||||||
ChatMessageType::System => {}
|
ChatMessageType::System => {}
|
||||||
ChatMessageType::User => {
|
ChatMessageType::User => {
|
||||||
let answer = match ai_client.send_question(&chat_id,question_id, ¶ms.content, &ai_model, Some(json!(params.metadata))).await {
|
let answer = match ai_client.send_question(&workspace_id, &chat_id,question_id, ¶ms.content, &ai_model, Some(json!(params.metadata))).await {
|
||||||
Ok(response) => response,
|
Ok(response) => response,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Failed to send question to AI: {}", err);
|
error!("Failed to send question to AI: {}", err);
|
||||||
|
|
|
||||||
|
|
@ -241,8 +241,8 @@ pub fn get_configuration() -> Result<Config, anyhow::Error> {
|
||||||
region: get_env_var("APPFLOWY_S3_REGION", ""),
|
region: get_env_var("APPFLOWY_S3_REGION", ""),
|
||||||
},
|
},
|
||||||
appflowy_ai: AppFlowyAISetting {
|
appflowy_ai: AppFlowyAISetting {
|
||||||
port: get_env_var("APPFLOWY_AI_SERVER_PORT", "5001").into(),
|
port: get_env_var("AI_SERVER_PORT", "5001").into(),
|
||||||
host: get_env_var("APPFLOWY_AI_SERVER_HOST", "localhost").into(),
|
host: get_env_var("AI_SERVER_HOST", "localhost").into(),
|
||||||
},
|
},
|
||||||
grpc_history: GrpcHistorySetting {
|
grpc_history: GrpcHistorySetting {
|
||||||
addrs: get_env_var("APPFLOWY_GRPC_HISTORY_ADDRS", "http://localhost:50051"),
|
addrs: get_env_var("APPFLOWY_GRPC_HISTORY_ADDRS", "http://localhost:50051"),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue