小技巧,Open WebUI 优化

换过之后页面加载速度什么的会有提升么 :tieba_087:

3 个赞

很快的。
之前左边的对话条目要好久,换完之后刷刷的。

1 个赞

还是重新设置方便,5分钟搞定 :rofl:

2 个赞

我刚刚试了一下,完整迁移成功了,似乎并不需要单独导出配置,所有对话、配置都在数据库里。

PostgreSQL 数据库迁移指南

  1. 创建一个空的 PostgreSQL 数据库

  2. 关闭 Open WebUI

  3. 设置 DATABASE_URL 环境变量,指向新创建的 PostgreSQL 数据库。

    environment:
      - DATABASE_URL=postgres://用户名:口令@ip:5432/数据库名
      - DATABASE_POOL_SIZE=10
      - DATABASE_POOL_MAX_OVERFLOW=20
      - ENABLE_OLLAMA_API=false
  1. 启动 Open WebUI 并尝试访问网站。这应该会强制创建数据库的图表。

  2. 再次关闭 Open WebUI

  3. 在某个位置创建一个新目录

    mkdir sqlite-to-postgres-migration
    cd sqlite-to-postgres-migration
    
  4. 初始化一个新的 Node.js 项目

    npm init -y
    npm install sqlite3 pg
    
  5. 从现有的 WebUI 部署中复制 webui.db 文件。该文件位于:

    <webui-root>/backend/data/webui.db
    
  6. 在新目录中创建以下脚本(修改原先数据库路径以及postgres数据库连接信息),例如命名为migrate.js

// Credit goes to Anthropic Claude Sonnet 3.5 for helping write this script!
const sqlite3 = require('sqlite3').verbose();
const { Client } = require('pg');
const fs = require('fs').promises;

// Configuration
const SQLITE_DB_PATH = 'webui.db'; // 改成webui.db所在目录,默认为当前目录

//这里修改数据库相关信息
const PG_CONFIG = {
  host: 'CONFIGURE ME',
  port: 5432,
  database: 'CONFIGURE ME',
  user: 'CONFIGURE ME',
  password: 'CONFIGURE ME',
  ssl: false
};

// Helper function to convert SQLite types to PostgreSQL types
function sqliteToPgType(sqliteType) {
  switch (sqliteType.toUpperCase()) {
    case 'INTEGER': return 'INTEGER';
    case 'REAL': return 'DOUBLE PRECISION';
    case 'TEXT': return 'TEXT';
    case 'BLOB': return 'BYTEA';
    default: return 'TEXT';
  }
}

// Helper function to handle reserved keywords
function getSafeIdentifier(identifier) {
  const reservedKeywords = ['user', 'group', 'order', 'table', 'select', 'where', 'from', 'index', 'constraint'];
  return reservedKeywords.includes(identifier.toLowerCase()) ? `"${identifier}"` : identifier;
}

async function migrate() {

  // Connect to SQLite database
  const sqliteDb = new sqlite3.Database(SQLITE_DB_PATH);

  // Connect to PostgreSQL database
  const pgClient = new Client(PG_CONFIG);
  await pgClient.connect();

  try {
    // Get list of tables from SQLite
    const tables = await new Promise((resolve, reject) => {
      sqliteDb.all("SELECT name FROM sqlite_master WHERE type='table'", (err, rows) => {
        if (err) reject(err);
        else resolve(rows);
      });
    });

    for (const table of tables) {
      const tableName = table.name;

      // Skip "migratehistory" and "alembic_version" tables
      if (tableName === "migratehistory" || tableName === "alembic_version") {
        console.log(`Skipping table: ${tableName}`);
        continue;
      }

      const safeTableName = getSafeIdentifier(tableName);
      console.log(`Checking table: ${tableName}`);

      // Check if table exists in PostgreSQL and has any rows
      const result = await pgClient.query(`SELECT COUNT(*) FROM ${safeTableName}`);
      const rowCount = parseInt(result.rows[0].count, 10);

      if (rowCount > 0) {
        console.log(`Skipping table: ${tableName} because it has ${rowCount} existing rows`);
        continue;
      }

      console.log(`Migrating table: ${tableName}`);

      // Get table schema from PostgreSQL to determine column types
      const pgSchema = await pgClient.query(
        `SELECT column_name, data_type
         FROM information_schema.columns
         WHERE table_name = $1`,
         [safeTableName]
      );

      const pgColumnTypes = {};
      pgSchema.rows.forEach(col => {
        pgColumnTypes[col.column_name] = col.data_type;
      });

      // Get table schema from SQLite
      const schema = await new Promise((resolve, reject) => {
        sqliteDb.all(`PRAGMA table_info(${tableName})`, (err, rows) => {
          if (err) reject(err);
          else resolve(rows);
        });
      });

      // Create table in PostgreSQL if it doesn't exist
      const columns = schema.map(col => `${getSafeIdentifier(col.name)} ${sqliteToPgType(col.type)}`).join(', ');
      await pgClient.query(`CREATE TABLE IF NOT EXISTS ${safeTableName} (${columns})`);

      // Get data from SQLite
      const rows = await new Promise((resolve, reject) => {
        sqliteDb.all(`SELECT * FROM ${tableName}`, (err, rows) => {
          if (err) reject(err);
          else resolve(rows);
        });
      });

      // Insert data into PostgreSQL
      for (const row of rows) {
        const columns = Object.keys(row).map(getSafeIdentifier).join(', ');
        const values = Object.entries(row).map(([key, value]) => {
          const columnType = pgColumnTypes[key]; // Get the type of the column in PostgreSQL

          // Handle boolean conversion for PostgreSQL
          if (columnType === 'boolean') {
            return value === 1 ? 'true' : 'false'; // Explicitly convert 1 to 'true' and 0 to 'false'
          }
          if (value === null) return 'NULL'; // Handle NULL values
          return typeof value === 'string' ? `'${value.replace(/'/g, "''")}'` : value; // Handle string escaping
        }).join(', ');

        // Insert data into PostgreSQL
        await pgClient.query(`INSERT INTO ${safeTableName} (${columns}) VALUES (${values})`);
      }

      console.log(`Migrated ${rows.length} rows from ${tableName}`);
    }

    console.log("Migration completed successfully!");
  } catch (error) {
    console.error("Error during migration:", error);
  } finally {
    // Close database connections
    sqliteDb.close();
    await pgClient.end();
  }
}

migrate();
  1. 运行脚本
node migrate.js

正常的话则不会报错,此时运行open-webui发现迁移成功,配置、对话都在

21 个赞

单独导一下对话,安全,毕竟重要数据是对话。

1 个赞

挺好的 抽空迁移了下 谢谢分享

5 个赞

20G的对话数据怎么迁移 :smirk:

感谢分享,有空迁移一下

你20G的对话数据,Open webui是怎么跑的啊。 机器强悍。。。。。

写程序读sqllite,写psql,1000条一提交。

3 个赞


每天的数据库日志大小 :smirk:
迁移服务器的时候上传数据库要几个小时
前几天删了下chat表 不然最新版本都更不了

你这不是psql了。 你现在不需要psql了, 要需要 Greenplum。

我1g内存的小鸡部署上去直接卡死,ssh都连不上去了,只能重装 :clown_face:

1 个赞

可以给我们测试一下 Greenplum,你这也是大模型和大数据相结合了。
用Greenplum好处,就是不用再关心数据存储了。

这是啥 新出的吗 之前没这个配置

我768M的内存的小鸡部署的还是挺流畅的,当然只是我一个人用

2 个赞

Greenplum是 psql的大数据版本,接口兼容 psql的。

简单了解了下 不知道能优化多少 有空看看

主要是解决存储问题,不用再关心数据备份,数据过大等等大量数据引发的问题。

感谢大佬 成功用这个脚本迁移了

2 个赞

对话可以先设置里导出,然后新数据库里再设置界面上导入啊?下午试了下,配置可以导入,对话好像没反应。