Replies: 5 comments 5 replies
-
| 
         3.7 设计方案: Document 表设计方案1. 数据库模型设计基于项目现有的数据库结构和需求,我设计了  
 documents 表/* eslint-disable sort-keys-fix/sort-keys-fix  */
import { 
  boolean, 
  index, 
  integer, 
  jsonb, 
  pgTable, 
  text, 
  uniqueIndex, 
  varchar 
} from 'drizzle-orm/pg-core';
import { createInsertSchema } from 'drizzle-zod';
import { idGenerator } from '@/database/utils/idGenerator';
import { LobeDocument, LobeDocumentPage } from '@/types/document';
import { timestamps } from './_helpers';
import { files } from './file';
import { users } from './user';
export const documents = pgTable(
  'documents',
  {
    id: text('id')
      .$defaultFn(() => idGenerator('documents'))
      .primaryKey(),
    
    // 基本信息
    title: text('title'),
    content: text('content'),
    source: text('source').notNull(), // 文件路径或网页URL
    fileType: varchar('file_type', { length: 255 }).notNull(),
    filename: text('filename'),
    
    // 统计信息
    totalCharCount: integer('total_char_count').notNull(),
    totalLineCount: integer('total_line_count').notNull(),
    
    // 元数据
    metadata: jsonb('metadata').$type<Record<string, any>>(),
    
    // 页面/块数据
    pages: jsonb('pages').$type<LobeDocumentPage[]>(),
    
    // 来源类型
    sourceType: text('source_type', { enum: ['file', 'web', 'api'] }).notNull(),
    
    // 关联文件(可选)
    fileId: text('file_id').references(() => files.id, { onDelete: 'set null' }),
    
    // 用户关联
    userId: text('user_id')
      .references(() => users.id, { onDelete: 'cascade' })
      .notNull(),
    clientId: text('client_id'),
    
    // 时间戳
    ...timestamps,
  },
  (table) => ({
    sourceIdx: index('documents_source_idx').on(table.source),
    fileTypeIdx: index('documents_file_type_idx').on(table.fileType),
    fileIdIdx: index('documents_file_id_idx').on(table.fileId),
    clientIdUnique: uniqueIndex('documents_client_id_user_id_unique').on(
      table.clientId, 
      table.userId
    ),
  }),
);
export type NewDocument = typeof documents.$inferInsert;
export type DocumentItem = typeof documents.$inferSelect;
export const insertDocumentSchema = createInsertSchema(documents);document_topics 关联表为了实现 document 与 topic 的多对多关联,我们需要创建一个关联表: import { pgTable, primaryKey, text } from 'drizzle-orm/pg-core';
import { createdAt } from './_helpers';
import { documents } from './document';
import { topics } from './topic';
import { users } from './user';
export const documentTopics = pgTable(
  'document_topics',
  {
    documentId: text('document_id')
      .notNull()
      .references(() => documents.id, { onDelete: 'cascade' }),
    
    topicId: text('topic_id')
      .notNull()
      .references(() => topics.id, { onDelete: 'cascade' }),
    
    userId: text('user_id')
      .references(() => users.id, { onDelete: 'cascade' })
      .notNull(),
    
    createdAt: createdAt(),
  },
  (t) => ({
    pk: primaryKey({ columns: [t.documentId, t.topicId] }),
  }),
);
export type NewDocumentTopic = typeof documentTopics.$inferInsert;
export type DocumentTopicItem = typeof documentTopics.$inferSelect;关系定义在 relations.ts 中添加相关关系定义: // 在 relations.ts 文件中添加
import { documents, documentTopics } from './document';
// Document 与 File 的关系
export const documentsRelations = relations(documents, ({ one, many }) => ({
  file: one(files, {
    fields: [documents.fileId],
    references: [files.id],
  }),
  topics: many(documentTopics),
}));
// Document 与 Topic 的关联关系
export const documentTopicsRelations = relations(documentTopics, ({ one }) => ({
  document: one(documents, {
    fields: [documentTopics.documentId],
    references: [documents.id],
  }),
  topic: one(topics, {
    fields: [documentTopics.topicId],
    references: [topics.id],
  }),
}));
// 在 topicRelations 中添加 documents 关系
export const topicRelations = relations(topics, ({ one, many }) => ({
  session: one(sessions, {
    fields: [topics.sessionId],
    references: [sessions.id],
  }),
  documents: many(documentTopics),
}));2. 业务逻辑设计Document 的业务逻辑
 使用场景
 3. 类型定义完善为了更好地支持 Document 表的使用,我们可以在类型定义中添加一些辅助类型: // 在 src/types/document.ts 中添加
/**
 * 文档来源类型
 */
export enum DocumentSourceType {
  FILE = 'file',
  WEB = 'web',
  API = 'api',
}
/**
 * 文档与 Topic 的关联类型
 */
export interface DocumentTopicRelation {
  documentId: string;
  topicId: string;
  userId: string;
  createdAt: Date;
}
/**
 * 扩展的文档对象,包含关联信息
 */
export interface DocumentWithRelations extends LobeDocument {
  topics?: Array<{
    id: string;
    title: string;
  }>;
  file?: {
    id: string;
    name: string;
    url: string;
  };
}总结这个设计方案提供了一个灵活且功能完善的 Document 表结构,能够满足存储不同来源的文档内容、与 Topic 关联作为上下文、以及可选地关联到文件的需求。该设计遵循了项目现有的数据库设计风格和约定,并提供了必要的索引和关系定义,以确保高效的查询性能。 通过这个设计,LobeChat 将能够更好地管理和利用文档内容,无论是来自本地文件还是 Web 搜索结果,从而增强对话的上下文理解和知识检索能力。  | 
  
Beta Was this translation helpful? Give feedback.
-
| 
         需要对旧数据表做清理吗,让数据表小一点。如果是的话是怎么做呢?  | 
  
Beta Was this translation helpful? Give feedback.
-
| 
         大佬,当前是不是去除了对话界面上传PDF的分块和Embedding的功能呀?这个挺好的,因为有时候分块会导致读取原文信息不全面,但是这样有些文档字数会超过模型的限制(比如某些论文),从而引起报错(报错提示超过上下文窗口数),所以能不能增加一个回退机制呢?比如在当前文档超过上下文窗口限制时转为以前的分块,或者自动忽略溢出的部分呢?  | 
  
Beta Was this translation helpful? Give feedback.
-
| 
         大佬,在之前对话中已经上传过的文件,怎么在新对话直接引用呢?  | 
  
Beta Was this translation helpful? Give feedback.
-
| 
         建议:文件上传中的图片上传,能否启用辅助模型呢(主要起到OCR的作用),这样一些不支持图片上传的模型就可以截图进行文本内容提问了  | 
  
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
背景
设计思路
上传文件改造方案思路:
进展
Beta Was this translation helpful? Give feedback.
All reactions