Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 339

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 392

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 394
Joyber 的博客

Ollama 不会直接识别丢进 blobs 文件夹的 gguf,不能简单复制进去;有两条路。

方案 A:给 Ollama 导入(如果你想用 ollama run / Qoder 调用)

  1. 找一个存放目录,例如:

    D:\ollama_local_models

    把 qwen2.5-coder-7b-instruct-q4_k_m.gguf 放这里。

  2. 在同一个文件夹新建文件,名字就叫 Modelfile(没有后缀),内容:

    FROM D:\ollama_local_models\qwen2.5-coder-7b-instruct-q4_k_m.gguf
    
    TEMPLATE "{{ if .System }}<|im_start|>system\n{{ .System }}<|im_end|>\n{{ end }}{{ if .Prompt }}<|im_start|>user\n{{ .Prompt }}<|im_end|>\n{{ end }}<|im_start|>assistant\n{{ .Response }}<|im_end|>"
    PARAMETER temperature 0.3
    PARAMETER num_ctx 8192
  3. 在这个目录打开 cmd,执行:

    ollama create qwen2.5-coder-local:7b -f Modelfile

    建好之后就可以:

    ollama run qwen2.5-coder-local:7b

    Qoder 里面 Model ID 填 qwen2.5-coder-local:7b。

⚠️:执行 create 的时候,Ollama 会把权重复制一份到它自己的 blob 存储,会占用双倍磁盘。

方案 B:直接给 llama.cpp server 使用(推荐,不复制)

随便放,比如 D:\gguf\qwen2.5-coder-7b-instruct-q4_k_m.gguf,启动命令直接指向这个路径,只用一份文件,省空间,适合你手动下载的 gguf。

llama-server -m D:\gguf\qwen2.5-coder-7b-instruct-q4_k_m.gguf -ngl 99 -c 8192 --port 8080

然后 Qoder 连 [http://127.0.0.1:8080/v1](http://127.0.0.1:8080/v1)。

补充

  • 不要手动往 %LOCALAPPDATA%\ollama\models\blobs 丢 gguf,无效,索引对不上。
  • 如果只是想省事,就继续用 ollama pull,不用手动下。
  • 如果是分卷 gguf,Modelfile 里面写:

    FROM D:\ollama_local_models\qwen2.5-coder-7b-instruct-q4_k_m-*.gguf

image.png

下面逐个说明,所有都是 Demucs 的预训练分离模型,后缀含义:

  • q = quantized(量化版):体积更小、速度更快,画质轻微下降,适合低配机器
  • ft = fine-tuned(微调版)
  • 6s = 6 轨分离
模型分离轨道特点适合场景
htdemucs4 轨:人声、鼓、贝斯、其他Demucs v4 默认模型,均衡,速度、质量折中日常分离,大多数歌曲首选
htdemucs_ft4 轨:人声、鼓、贝斯、其他在 htdemucs 基础上微调,4 轨里音质最好,速度稍慢需要高质量分轨、做翻唱、混音提取
htdemucs_6s6 轨:人声、鼓、贝斯、吉他、钢琴、其他额外分出吉他、钢琴;代价是单轨纯净度略低于上面两个需要单独提取吉他或者钢琴
hdemucs_mmi4 轨v3 老版本混合 Demucs,在 MusDB + 额外 800 首歌训练兼容老素材,一般不优先选
mdx4 轨MDX 挑战赛夺冠模型,仅在 MusDB HQ 数据集训练,速度较快早期热门模型,人声分离不错,但整体弱于 htdemucs 系列
mdx_extra4 轨mdx 的加强版,加入更多额外训练数据,纯净度优于原版 mdx如果 htdemucs 对某首歌翻车,可以换它尝试
mdx_q4 轨mdx 的量化压缩版本,占用显存更低、速度更快,音质小幅缩水显卡弱、内存小的电脑
mdx_extra_q4 轨mdx_extra 的量化版低配机器,想用 mdx_extra 时选择

快速选择建议

  • ✅ 追求最好质量:htdemucs_ft
  • ✅ 兼顾速度和质量:htdemucs
  • ✅ 想要单独分出吉他、钢琴:htdemucs_6s
  • ✅ 电脑配置低、显存小:优先带 _q 的模型
  • ✅ 前面几个模型分离效果差:试 mdx_extra

如果你主要用来提取鼓轨(正好你下拉框选的是“鼓声+其他”):优先 htdemucs_ft,鼓的分离干净度通常最优。

image.png

报错原因:这个 mp3 文件内部帧采样率乱跳,一部分帧是 32000,一部分突然跳到 44100,你这个音轨分离器内置的 Mp3FileReader 不支持这种动态变采样率的 MP3。

下面两条命令任选,第一条输出 WAV(最稳,推荐给 Demucs),第二条输出固定采样率 MP3。

把 input.mp3 换成你的源文件名。

方案 1|转成固定 44100 WAV(优先推荐)

ffmpeg -i input.mp3 -ar 44100 -ac 2 -c:a pcm_s16le -y fixed.wav
  • -ar 44100:强制固定采样率 44100
  • -ac 2:立体声
  • pcm_s16le:标准 16bit PCM,音轨分离器读取无压力

方案 2|重编码为固定采样率 MP3

ffmpeg -i input.mp3 -ar 44100 -ac 2 -c:a libmp3lame -b:a 320k -y fixed.mp3

如果你想统一成 32000,只需要把上面的 -ar 44100 改成 -ar 32000。

说明:不能用 -c:a copy,copy 会原样保留文件里错乱的采样帧,报错依旧,必须重新编码。

转完之后把 fixed.wav 丢进你这个音轨分离器就不会报这条错误。

abstract 抽象类(PHP)

作用

  1. 约束子类必须实现指定方法:抽象方法只有声明、没有实现,子类继承后必须重写这个抽象方法,否则子类也得标记为 abstract,不能实例化。用来统一接口规范。
  2. 可以放通用共用代码:和接口 interface 不一样,抽象类里面可以写已经实现好的普通方法、属性,子类直接复用。
  3. 本身不能 new 实例,只能被继承,用来做基类、模板骨架(模板方法模式非常常用)。

对比一句话:

  • interface:全部都是契约,不能写实现,一个类可以多实现
  • abstract class:一半契约(abstract方法)+一半现成代码,只能单继承

写法规则(PHP)

  1. 类前面加 abstract
  2. 抽象方法:前面 abstract,没有函数体,以分号结尾,不能有 {}
  3. 普通方法、属性、常量正常写,随便写实现
  4. 子类 extends 抽象类,必须全部实现父类所有抽象方法
  5. 抽象类不能 new

最简示例

<?php
abstract class CarrierBase
{
    // 抽象方法:子类必须实现
    abstract public function sendOrder(array $orderData): bool;
    abstract public function cancelOrder(int $orderId): bool;

    // 已经实现的公共方法,子类直接继承复用
    protected function log(string $msg): void
    {
        echo date('Y-m-d H:i:s') . ' ' . $msg . PHP_EOL;
    }
}

// 子类实现抽象类
class SelfCourierCarrier extends CarrierBase
{
    public function sendOrder(array $orderData): bool
    {
        $this->log('自有骑手接单:' . $orderData['id']);
        return true;
    }

    public function cancelOrder(int $orderId): bool
    {
        $this->log('自有骑手取消订单:' . $orderId);
        return true;
    }
}

// $base = new CarrierBase(); // 报错!抽象类不能实例化
$carrier = new SelfCourierCarrier();
$carrier->sendOrder(['id' => 1001]);

结合你上面跑腿运力场景的例子(贴合你的 CarrierInterface)

你现在是 CarrierInterface 接口;如果很多运力都共用一套日志、组装请求的逻辑,就适合改成抽象基类:

abstract class AbstractCarrier implements CarrierInterface
{
    // 公共通用能力,所有运力复用
    protected function buildOrderParam(array $raw): array
    {
        return [
            'order_no' => $raw['order_sn'],
            'addr_from' => $raw['from_address'],
            'addr_to' => $raw['to_address'],
        ];
    }
}

class SelfCourierCarrier extends AbstractCarrier
{
    public function dispatch(array $order): bool
    {
        $param = $this->buildOrderParam($order);
        // 自有骑手分发逻辑
        return true;
    }
}

class ThirdPartyCarrier extends AbstractCarrier
{
    public function dispatch(array $order): bool
    {
        $param = $this->buildOrderParam($order);
        // 调用UU/闪送接口
        return true;
    }
}

重点坑点

  1. 抽象方法不能写body:abstract public func(); ✅,带大括号 ❌
  2. 子类实现的方法,访问权限不能比父抽象方法更严格(父public,子类不能改成protected/private)
  3. 抽象类可以没有任何抽象方法(可以,但意义不大,仅用来禁止直接new基类)
  4. 一个类只能继承一个抽象类(PHP单继承)

什么时候选 abstract,什么时候选 interface

  • 多个子类有大量重复共用代码 → abstract 抽象类
  • 只定义调用契约、没有公共逻辑、一个类需要多套契约 → interface

image.png

这是 Mermaid 语法,专门用来在 Markdown 里画流程图,很多平台支持:Typora、语雀、飞书文档、Gitlab、Github、Notion、Trae/VSCode 插件等

你这段是 graph TD,TD = Top Down,从上到下的流程图

基础语法速记

graph TD
    起点 --> 终点       // 箭头连线
    节点ID["显示文字"]  // 方框节点,最常用
    节点ID(圆角文字)    // 圆角框
    节点ID{判断}        // 菱形判断框
graph TD:从上往下
graph LR:从左往右(LR=Left Right,后端架构图最常用)

拆解你这段代码

graph TD
    A["跑腿员端 API (api/errand)"] --> S1["ErrandCourierService"]
    A --> S2["ErrandOrderService"]
    B["管理平台 API (admin/errand)"] --> S1
    B --> S3["ErrandCarrierService"]
    C["用户端下单 (api ErrandController)"] --> S2
    S3 --> M["CarrierManager (运力解析)"]
    M --> I["CarrierInterface"]
    I --> R1["SelfCourierCarrier (自有骑手)"]
    I --> R2["ThirdPartyCarrier (UU/闪送 预留)"]
    S2 --> L["ErrandOrderStatusLog / ErrandTimeNode / ErrandWorkRecord"]
  • A、S1、S2:是节点唯一ID,随便起名,只用来内部连线,不展示
  • ["xxx"]:方括号,矩形框,显示里面的文字
  • -->:单向箭头,表示依赖/调用关系(A 调用 S1)

快速上手规则(记住4条就够用)

  1. 开头固定:graph TD(竖向)或者 graph LR(横向,推荐画架构)
  2. 每个节点格式:ID["展示文本"],ID不能重复
  3. 连线:ID1 --> ID2
  4. 一行一条连线,换行不影响

改成横向架构图版本(后端结构图一般用LR更好看)

graph LR
    A["跑腿员端 API (api/errand)"] --> S1["ErrandCourierService"]
    A --> S2["ErrandOrderService"]
    B["管理平台 API (admin/errand)"] --> S1
    B --> S3["ErrandCarrierService"]
    C["用户端下单 (api ErrandController)"] --> S2
    S3 --> M["CarrierManager (运力解析)"]
    M --> I["CarrierInterface"]
    I --> R1["SelfCourierCarrier (自有骑手)"]
    I --> R2["ThirdPartyCarrier (UU/闪送 预留)"]
    S2 --> L["ErrandOrderStatusLog / ErrandTimeNode / ErrandWorkRecord"]

怎么运行预览

VSCode 装插件:Markdown Preview Mermaid Support,打开md直接看;
飞书/语雀文档,直接粘贴这段代码,选择Mermaid代码块即可渲染。

扩展小补充(你画架构常用)

  • 虚线箭头:-.->
  • 标注文字箭头:A -- 调用 --> B

    graph LR
    A["服务A"] -- 同步调用 --> B["服务B"]
    B -.-> C["异步回调"]