博客 (117)

一、安装 Ollama

官网下载安装 Ollama。

你可以更改大模型存放目录,也可以开放远程访问

查看版本号:

ollama --version


二、在 shell 中安装和运行模型

Models 中选择一个你想部署的模型,复制安装命令,并在终端中执行。

官方建议:应该至少有 8 GB 的 RAM 来运行 7b 版本,16 GB 的 RAM 来运行 13b 版本,32 GB 的 RAM 来运行 33b 版本

本文以 deepseek-r1:7b 为例。

下载模型

ollama pull deepseek-r1:7b

Tip: 下载即将完成时速度可能会变得非常慢,只要按 Ctrl+C,再重新执行一次命令,就会继续正常下载。

显示模型信息

ollama show deepseek-r1:7b

运行模型(一次性响应)

ollama run deepseek-r1:7b "写一首诗"

运行模型(进入聊天模式)

ollama run deepseek-r1:7b

结束当前会话

/bye

列出所有模型

ollama list

列出当前加载的模型

ollama ps

停止当前正在运行的模型

ollama stop deepseek-r1:7b


三、使用 REST API 调用模型

修改端口

ollama serve --port 11434

/api/generate 接口:生成一次性响应

curl http://localhost:11434/api/generate -d '{
  "model": "deepseek-r1:7b",
  "prompt":"为什么天空是蓝色的?"
}'

/api/chat 接口:与模型聊天

curl http://localhost:11434/api/chat -d '{
  "model": "deepseek-r1:7b",
  "messages": [
    { "role": "user", "content": "你好呀!" }
  ]
}'


四、在 .NET 中调用

1、直接 HTTP 调用(基础方案)

    创建 HttpClient,使用 PostAsJsonAsync 请求,使用 ReadFromJsonAsync 读取结果。

2、使用 OllamaSharp 库(推荐方案)

    创建 OllamaApiClient,使用 SelectedModel 设置模型,使用 GenerateAsync 获得结果。或创建对话 ollama.Chat(),并 Send 内容。

3、.NET Aspire 集成(企业级方案)

    适合微服务架构,结合容器化部署。


OllamaSharp 库”和“.NET Aspire 集成”两种方案怎么选?

OllamaSharp 库:定位轻量级模型交互 SDK,适用于独立应用、微服务中的 AI 组件等场景,技术复度低,支持模型对话/生成/管理、流式响应、多模态支持,需自行实现监控、熔断。

.NET Aspire 集成:定位企业级云原生 AI 服务编排框架,适用于多服务协同的分布式系统,技术复度高,支持服务编排、健康检查、弹性伸缩、混合云部署,内置可观测性仪表盘、自动故障转移。

决策建议:初创项目用 OllamaSharp 快速试错,用户量破千后通过 Aspire 重构。两者并非互斥,可在 Aspire 中封装 OllamaSharp 客户端,兼顾灵活性与运维能力。

xoyozo 2 个月前
2,872
  1. 国家智慧教育公共服务平台 https://gjzwfw.www.gov.cn/

  2. 中国裁判文书网 https://wenshu.court.gov.cn/

  3. 国家企业信用信息公示系统 https://gs.gsxt.gov.cn/

  4. 国家社会保险服务平台 https://si.12333.gov.cn/

  5. 天地图 https://www.tianditu.gov.cn/

  6. 国家统计局 https://www.stats.gov.cn/

  7. 中国商标网 https://sbj.cnipa.gov.cn/sbj/

  8. 国家法律法规数据库 https://flk.npc.gov.cn/

  9. 中国专利公布公告网 http://epub.cnipa.gov.cn/

  10. 国家标准全文公开系统 https://openstd.samr.gov.cn/bzgk/gb/

  11. 国家药品监督管理局 https://www.nmpa.gov.cn/datasearch/

  12. 食品安全抽检公布结果查询系统 https://spcjsac.gsxt.gov.cn/

  13. 发票查验平台 http://inv-veri.chinatax.gov.cn/

  14. 中国关键词 http://keywords.china.org.cn/

  15. 工信部申诉受理中心 https://ythzxfw.miit.gov.cn/

  16. 合同示范文本库 https://htsfwb.samr.gov.cn/

  17. 中国法律服务网 https://www.12348.gov.cn/

  18. 中国庭审公开网 https://tingshen.court.gov.cn/

非 gov 网站

  1. 终身教育平台 https://le.ouchn.cn/

  2. 国家数字图书馆 https://www.nlc.cn/

  3. 国家哲学社会科学文献 https://www.ncpssd.cn/

  4. 国家高等教育智慧教育平台 https://www.chinaooc.com.cn/

  5. 职业教育专业教学资源库 https://zyk.icve.com.cn/


转自 一网一匠 8 个月前
1,019

截止 2024 年 9 月,CZDB 数据已支持 JAVA、PHP、C、Node.js、Python 语言解析,但官方迟迟未推出 C# / ASP.NET 的版本,于是我参照前面几种语言版本写了 C# 版,支持 IPv4 与 IPv6,实测查询速度,CZDB 版的 MEMORY 模式比原来的 DAT 版数据库快数百倍(具体要看磁盘和内存的读写速度)。能够有效降低 CPU 的使用率,特别是在需要频繁查询 IP 属地的应用场景(譬如每个 HTTP 请求都要判断 IP 属地来决定是否允许访问)。

我要试试→

源代码已提交给纯真官方,相信很快就会有官方版本的 SDK。

xoyozo 1 年前
2,185

打开 JS 文件,查找:

o+=String.fromCharCode(t.charCodeAt(r)^i[(i[e]+i[s])%256]);

水印文字是从这个变量 o 输出来的,可以在这句的后面,“return o”的前面插入“console.log(o);”看到效果。

因为它是一行一行返回的,所以将

return o

改为下面的三目即可:

return o=='GoJS 3.0 evaluation'||o=='(c) 1998-2024 Northwoods Software'||o=='Not for distribution or production use'||o=='gojs.net'?'':o

修改方法来源于网络,仅供学习参考,请勿用于生产环境,请支持正版!

xoyozo 1 年前
2,741

微信网页开发 JS-SDK 官方文档介绍的获取地理位置接口示例是这样的:

wx.getLocation({
  type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
  success: function (res) {
    var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
    var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
    var speed = res.speed; // 速度,以米/每秒计
    var accuracy = res.accuracy; // 位置精度
  }});

实际上是这样的:

wx.getLocation({
  type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
  success: function (res) {
    // 网页位置信息授权点击“确定”按钮,以及允许后继续获取定位信息
  },
  fail: function (err) {
    // 获取定位信息失败(譬如:网页位置信息已授权,但操作系统定位已关闭)
  },
  cancel: function (err) {
    // 网页位置信息授权点击“拒绝”按钮
  }
});

顺便提一下如何关闭网页授权:

进入网页使用 JS-SDK 的公众号(可以在授权弹框中看到服务号名称),点击右上角人形图标,继续点击右上角三个点图标,选择设置,关闭“位置信息”。

授权框.png公众号设置.png

xoyozo 1 年前
1,207

.NET SDK 的版本 8.0.303 至少需要 MSBuild 的 17.8.3 版本。当前可用的 MSBuild 版本为 16.11.2.50704。请将在 global.json 中指定的 .NET SDK 更改为需要当前可用的 MSBuild 版本的旧版本。

解决方法:

运行 Visual Studio Installer,

选择相应 VS 版本进行修改,

切到“单个组件”,

勾选“.NET SDK (out of support)”,

点击修改并继续。

xoyozo 1 年前
2,132

POST

$.post('AjaxCases', {
    following: true,
    success: null,
    page: 1,
}, function (response) {
    console.log(response.data)
}, 'json').fail(function (xhr, status, error) {
    console.log(xhr.responseText);
});
[HttpPost]
public IActionResult AjaxCases([FromForm] AjaxCasesRequestModel req)
{
    bool? following = req.following;
    bool? success = req.success;
    int page = req.page;
}

提示:只能传输对象(Object),不能传输数组(Array)。


相关:axios 请求 .NET Core / .NET 5 / .NET 6

xoyozo 1 年前
1,396

SignalR 是一个开源的实时通信库,用于构建实时 Web 应用程序。它提供了一个简单的 API,可以在客户端和服务器之间建立持久连接,以便实时地推送数据。

与传统的 WebSocket 相比,SignalR 提供了更高级的功能和更简单的开发体验。下面是一些主要区别:

  • 支持多种传输方式:SignalR 可以使用多种传输方式,包括 WebSocket、Server-Sent Events(SSE)、长轮询和 Forever Frame。这使得 SignalR 在不同的环境中都能提供实时通信的能力,即使某些浏览器不支持 WebSocket,也可以使用其他传输方式。

  • 自动处理连接管理:SignalR 管理连接的生命周期,包括连接的建立、断开和重新连接。它会自动处理连接的失败和重新连接的逻辑,简化了开发人员的工作。

  • 服务器端推送:SignalR 允许服务器端主动推送消息给客户端,而不需要客户端发起请求。这使得实时通信变得更加高效和实时,适用于聊天应用、实时监控等场景。

  • 跨平台支持:SignalR 可以在多个平台上使用,包括 .NET、Java、JavaScript 等。这使得开发人员可以使用自己熟悉的语言和框架来构建实时应用程序。


微软官方提供了针对 ASP.NET Core Web 应用(Razor 页面)的详细教程,这里给出 MVC 版本入门教程。


最终将创建一个正常运行的聊天应用:

signalr-get-started-finished.png


创建 Web 应用项目

image.png

image.png


添加 SignalR 客户端库

在“解决方案资源管理器”>中,右键单击项目,然后选择“添加”“客户端库”。

在“添加客户端库”对话框中:

  • “提供程序”选择“unpkg”

  • “库”,请输入 @microsoft/signalr@latest。

  • 选择“选择特定文件”,展开“dist/browser”文件夹,然后选择 signalr.js 和 signalr.min.js。

  • 点击“安装” 。

image.png


创建 SignalR Hubs 类

using Microsoft.AspNetCore.SignalR;

/// <summary>
/// Hub 类管理连接、组和消息
/// </summary>
public class ChatHub : Hub
{
        /// <summary>
        /// 可通过已连接客户端调用 SendMessage,以向所有客户端发送消息
        /// </summary>
    public async Task SendMessage(string user, string message)
    {
        // Clients.All 向所有的客户端发送消息
        // ReceiveMessage 是客户端监听的方法
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

其父类 Hub 可管理连接、组和消息。这里演示的是向所有客户端发送消息。


配置 SignalR

打开 Program.cs,添加注入:

builder.Services.AddSignalR();

添加路由:

app.MapHub<ChatHub>("/chatHub");


添加 SignalR 客户端代码

视图页面:

<div class="container">
    <div class="row p-1">
        <div class="col-1">用户</div>
        <div class="col-5"><input type="text" id="userInput" /></div>
    </div>
    <div class="row p-1">
        <div class="col-1">消息</div>
        <div class="col-5"><input type="text" class="w-100" id="messageInput" /></div>
    </div>
    <div class="row p-1">
        <div class="col-6 text-end">
            <input type="button" id="sendButton" value="发送消息" />
        </div>
    </div>
    <div class="row p-1">
        <div class="col-6">
            <hr />
        </div>
    </div>
    <div class="row p-1">
        <div class="col-6">
            <ul id="messagesList"></ul>
        </div>
    </div>
</div>
<script src="~/lib/microsoft/signalr/dist/browser/signalr.min.js"></script>
<script src="~/js/chat.js"></script>

chat.js 文件:

"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

// 在连接建立之前禁用发送按钮
document.getElementById("sendButton").disabled = true;

connection.on("ReceiveMessage", function (user, message) {
    var li = document.createElement("li");
    document.getElementById("messagesList").appendChild(li);
    // 修改此处时应注意脚本注入问题
    li.textContent = `${user} says ${message}`;
});

connection.start().then(function () {
    document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click", function (event) {
    var user = document.getElementById("userInput").value;
    var message = document.getElementById("messageInput").value;
    connection.invoke("SendMessage", user, message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});


完成。在线示例:https://xoyozo.net/Demo/SignalRDemo






xoyozo 2 年前
2,534

推荐使用 SignalR 来平替 WebSocket,参考教程


【服务端(.NET)】

一、创建 WebSocketHandler 类,用于处理客户端发送过来的消息,并分发到其它客户端

public class WebSocketHandler
{
    private static List<WebSocket> connectedClients = [];

    public static async Task Handle(WebSocket webSocket)
    {
        connectedClients.Add(webSocket);

        byte[] buffer = new byte[1024];
        WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        while (!result.CloseStatus.HasValue)
        {
            string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
            Console.WriteLine($"Received message: {message}");

            // 处理接收到的消息,例如广播给其他客户端
            await BroadcastMessage(message, webSocket);

            result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        }

        connectedClients.Remove(webSocket);
        await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
    }

    private static async Task BroadcastMessage(string message, WebSocket sender)
    {
        foreach (var client in connectedClients)
        {
            if (client != sender && client.State == WebSocketState.Open)
            {
                await client.SendAsync(Encoding.UTF8.GetBytes(message), WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }
    }
}

二、在 Program.cs 或 Startup.cs 中插入:

// 添加 WebSocket 路由
app.UseWebSockets();
app.Use(async (context, next) =>
{
    if (context.Request.Path == "/chat")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await WebSocketHandler.Handle(webSocket);
        }
        else
        {
            context.Response.StatusCode = 400;
        }
    }
    else
    {
        await next();
    }
});

这里的路由路径可以更改,此处将会创建一个 WebSocket 连接,并将其传递给 WebSocketHandler.Handle 方法进行处理。

也可以用控制器来接收 WebSocket 消息。


【客户端(JS)】

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
    <title>WebSocket 示例(JS + ASP.NET)</title>
    <style>
        #list { width: 100%; max-width: 500px; }
        .tip { color: red; }
    </style>
</head>
<body>
    <h2>WebSocket 示例(JS + ASP.NET)</h2>
    <textarea id="list" readonly rows="20"></textarea>
    <div>
        <input type="text" id="msg" />
        <button onclick="fn_send()">发送</button>
        <button onclick="fn_disconnect()">断开</button>
    </div>
    <p id="tip_required">请输入要发送的内容</p>
    <p id="tip_closed">WebSocket 连接未建立</p>

    <script>
        var wsUrl = "wss://" + window.location.hostname + ":" + window.location.port + "/chat";
        var webSocket;
        var domList = document.getElementById('list');

        // 初始化 WebSocket 并连接
        function fn_ConnectWebSocket() {
            webSocket = new WebSocket(wsUrl);

            // 向服务端发送连接请求
            webSocket.onopen = function (event) {
                var content = domList.value;
                content += "[ WebSocket 连接已建立 ]" + '\r\n';
                domList.innerHTML = content;

                document.getElementById('tip_closed').style.display = 'none';

                webSocket.send(JSON.stringify({
                    msg: 'Hello'
                }));
            };

            // 接收服务端发送的消息
            webSocket.onmessage = function (event) {
                if (event.data) {
                    var content = domList.value;
                    content += event.data + '\r\n';
                    domList.innerHTML = content;
                    domList.scrollTop = domList.scrollHeight;
                }
            };

            // 各种情况导致的连接关闭或失败
            webSocket.onclose = function (event) {
                var content = domList.value;
                content += "[ WebSocket 连接已关闭,3 秒后自动重连 ]" + '\r\n';
                domList.innerHTML = content;

                document.getElementById('tip_closed').style.display = 'block';

                setTimeout(function () {
                    var content = domList.value;
                    content += "[ 正在重连... ]" + '\r\n';
                    domList.innerHTML = content;
                    fn_ConnectWebSocket();
                }, 3000); // 3 秒后重连
            };
        }

        // 检查连接状态
        function fn_IsWebSocketConnected() {
            if (webSocket.readyState === WebSocket.OPEN) {
                document.getElementById('tip_closed').style.display = 'none';
                return true;
            } else {
                document.getElementById('tip_closed').style.display = 'block';
                return false;
            }
        }

        // 发送内容
        function fn_send() {
            if (fn_IsWebSocketConnected()) {
                var message = document.getElementById('msg').value;
                document.getElementById('tip_required').style.display = message ? 'none' : 'block';
                if (message) {
                    webSocket.send(JSON.stringify({
                        msg: message
                    }));
                }
            }
        }

        // 断开连接
        function fn_disconnect() {
            if (fn_IsWebSocketConnected()) {
                // 部分浏览器调用 close() 方法关闭 WebSocket 时不支持传参
                // webSocket.close(001, "Reason");
                webSocket.close();
            }
        }

        // 执行连接
        fn_ConnectWebSocket();
    </script>
</body>
</html>


【在线示例】

https://xoyozo.net/Demo/JsNetWebSocket


【其它】

  • 服务端以 IIS 作为 Web 服务器,那么需要安装 WebSocket 协议

  • 一个连接对应一个客户端(即 JS 中的 WebSocket 对象),注意与会话 Session 的区别

  • 在实际项目中使用应考虑兼容性问题

  • 程序设计应避免 XSS、CSRF 等安全隐患

  • 参考文档:https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/websockets

xoyozo 2 年前
1,581

如果手机开启了自动横屏,那么网页就会跟着旋转,导致网页宽度变大,高度变小,页面布局不友好,我们可以通过判断屏幕方向 api,用 css 设置旋转。


HTML:

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
    <title>保持竖屏示例</title>
</head>
<body>
    <div id="app">
        <div class="page">
            <div>把手机横过来试试</div>
            <div>页面永远保持竖屏方向</div>
        </div>
    </div>
</body>
</html>

CSS:

body { margin: 0; }
.page { text-align: center; padding-top: 100px; }

@media screen and (orientation: landscape) {
    body { width: 100vh; height: 100vw; overflow: hidden; }
    .page.landscape-primary { transform: rotate(-90deg); transform-origin: top left; width: 100vh; height: 100vw; position: absolute; top: 100%; left: 0; }
    .page.landscape-secondary { transform: rotate(90deg); transform-origin: top left; width: 100vh; height: 100vw; position: absolute; top: 0; left: 100%; }
}

JS:

function fn_set_orientation() {
    var orientation = window.screen.orientation || window.screen.mozOrientation || window.screen.msOrientation;
    const div = document.querySelector('.page');
    console.log(orientation.type)
    switch (orientation.type) {
        case 'landscape-primary': {
            div.classList.remove('landscape-secondary');
            div.classList.add('landscape-primary');
            break;
        }
        case 'landscape-secondary': {
            div.classList.remove('landscape-primary');
            div.classList.add('landscape-secondary');
            break;
        }
        default: {
            div.classList.remove('landscape-primary');
            div.classList.remove('landscape-secondary');
            break;
        }
    }
}
window.addEventListener("orientationchange", function () {
    fn_set_orientation();
});
fn_set_orientation();

示例:

https://xoyozo.net/Demo/Orientation


xoyozo 2 年前
1,249