Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api/schemas/mysql.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ ORM:[`UsageLogDB`](../../src/models/db_models.py)
| `created_at` / `updated_at` | DATETIME | 创建 / 更新时间 |

索引:
- `uk_conversation_user_dataset_title(user_id, dataset_id, title)`
- `idx_chat_conversation_user_pinned_updated(user_id, is_pinned, updated_at)`
- `idx_chat_conversation_dataset_updated(dataset_id, updated_at)`

Expand Down
51 changes: 51 additions & 0 deletions migrations/versions/0014_20260607_add_conversation_unique_title.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""add unique title constraint for chat conversations

Java requires conversation titles to be unique within the same user and dataset.
Before adding the unique key, remove existing duplicates by keeping the newest
conversation row (largest id) for each ``(user_id, dataset_id, title)`` group.

Revision ID: 0014
Revises: 0013
Create Date: 2026-06-07
"""

from __future__ import annotations

from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op


revision: str = "0014"
down_revision: Union[str, None] = "0013"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.execute(
sa.text(
"""
DELETE c1 FROM chat_conversation c1
INNER JOIN chat_conversation c2
ON c1.user_id = c2.user_id
AND c1.dataset_id = c2.dataset_id
AND c1.title = c2.title
AND c1.id < c2.id
"""
)
)
op.create_unique_constraint(
"uk_conversation_user_dataset_title",
"chat_conversation",
["user_id", "dataset_id", "title"],
)


def downgrade() -> None:
op.drop_constraint(
"uk_conversation_user_dataset_title",
"chat_conversation",
type_="unique",
)
106 changes: 106 additions & 0 deletions scripts/db/add_aliyun_system_presets.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
-- Add Aliyun DashScope system presets for remote dev.
-- Do not store plaintext API keys in llm_system_preset.api_key.
-- api_key below is encrypted with the current tolink.llm.api-key.secret
-- using ApiKeyEncryptService AES-256-GCM format: base64(iv + cipherText + tag).

USE tolink_rag_db;

START TRANSACTION;

-- Provider: Tongyi Qianwen uses the project's existing provider_type "aliyun".
INSERT INTO llm_system_provider (
provider_type,
provider_name,
api_base_url,
is_active,
priority
)
VALUES (
'aliyun',
'Tongyi Qianwen (DashScope)',
'https://dashscope.aliyuncs.com/compatible-mode/v1',
TRUE,
99
)
ON DUPLICATE KEY UPDATE
provider_name = VALUES(provider_name),
api_base_url = VALUES(api_base_url),
is_active = TRUE,
priority = GREATEST(priority, VALUES(priority));

-- Ensure the preset models exist in the provider model catalog.
INSERT INTO llm_provider_model (
provider_id,
model_name,
capability,
is_active
)
SELECT p.id, m.model_name, m.capability, TRUE
FROM llm_system_provider p
JOIN (
SELECT 'qwen3.5-flash' AS model_name, 'CHAT' AS capability
UNION ALL SELECT 'text-embedding-v4', 'EMBEDDING'
UNION ALL SELECT 'qwen3-rerank', 'RERANK'
UNION ALL SELECT 'qwen-vl-max', 'VISION'
) m
WHERE p.provider_type = 'aliyun'
ON DUPLICATE KEY UPDATE
is_active = TRUE;

-- Active system presets are copied to new users as is_system_preset=true.
-- Existing matching presets are updated to this key and enabled.
INSERT INTO llm_system_preset (
provider_id,
model_name,
capability,
api_key,
is_active
)
SELECT p.id, m.model_name, m.capability,
'vIgEBTQxRc4g8WU4ghnMpwCOFiFAdN/AxaVwfGLa499SjFlsXJ/0HZ+a1A2qJdnokqPKM/yNlJ1SnF/3MU2+' AS api_key,
TRUE
FROM llm_system_provider p
JOIN (
SELECT 'qwen3.5-flash' AS model_name, 'CHAT' AS capability
UNION ALL SELECT 'text-embedding-v4', 'EMBEDDING'
UNION ALL SELECT 'qwen3-rerank', 'RERANK'
UNION ALL SELECT 'qwen-vl-max', 'VISION'
) m
WHERE p.provider_type = 'aliyun'
ON DUPLICATE KEY UPDATE
api_key = VALUES(api_key),
is_active = TRUE,
updated_at = CURRENT_TIMESTAMP;

-- Verification query.
SELECT
p.provider_type,
p.provider_name,
p.api_base_url,
s.model_name,
s.capability,
s.is_active
FROM llm_system_preset s
JOIN llm_system_provider p ON p.id = s.provider_id
WHERE p.provider_type = 'aliyun'
AND (s.model_name, s.capability) IN (
('qwen3.5-flash', 'CHAT'),
('text-embedding-v4', 'EMBEDDING'),
('qwen3-rerank', 'RERANK'),
('qwen-vl-max', 'VISION')
)
ORDER BY FIELD(s.capability, 'CHAT', 'EMBEDDING', 'RERANK', 'VISION');

COMMIT;

-- Rollback if needed:
-- DELETE s
-- FROM llm_system_preset s
-- JOIN llm_system_provider p ON p.id = s.provider_id
-- WHERE p.provider_type = 'aliyun'
-- AND (s.model_name, s.capability) IN (
-- ('qwen3.5-flash', 'CHAT'),
-- ('text-embedding-v4', 'EMBEDDING'),
-- ('qwen3-rerank', 'RERANK'),
-- ('qwen-vl-max', 'VISION')
-- );
1 change: 1 addition & 0 deletions scripts/db/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ CREATE TABLE IF NOT EXISTS chat_conversation (
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

UNIQUE KEY uk_conversation_user_dataset_title (user_id, dataset_id, title),
INDEX idx_chat_conversation_user_pinned_updated (user_id, is_pinned, updated_at),
INDEX idx_chat_conversation_dataset_updated (dataset_id, updated_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=10000 COMMENT '对话表';
Expand Down
Loading
Loading