skip to content
声控烤箱 | KazooTTT 博客

Notes(115) RSS feed

71. [前端] __dirname is not defined in ES module scope

Updated:

__dirname Is not Defined in ES Module Scope

在 package.json 中的 type = module 的项目中,我创建了一个 ts 文件,类型是 esm 的类型。

这里的报错是因为我们错误的使用了 module 的语法到 esm 的文件中,要解决这个问题的方法有两种,第一种改为 module,另一种是改为 esm 的写法。

首先是第一种改为 module 的写法,那就是把 import 改为 require,然后由于我们这里是 module 的项目,所以需要修改一下 ts 文件的后缀 ts 改为 cts。

一个供参考的例子:GitHub - shawnsparks/typescript-esm: Explore different usage patterns of ES modules with Typescript

然后是第二种,文件、路径相关的改为 esm 的写法。

import { fileURLToPath } from "url"
import path from "path"
// 获取当前模块的目录路径
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

72. [软件] Possible Causes and Solutions for Focusee Switching System Audio to Speaker Playback forcibly

Updated:

Possible Causes and Solutions for Focusee Switching System Audio to Speaker Playback Forcibly

On macOS, when I wanted to use Focusee to record system audio, I followed its guide to install Gemoo Speaker.

Although switching the output device to Gemoo Speaker allowed me to record the system audio, it played the sound directly through the speakers.

Later, I found out that it was because I had installed BlackHole2ch. After uninstalling this virtual sound card, Focusee was able to record the sound through the headphones properly using Gemoo Speaker.

Uninstallation method:

Navigate to the folder /Library/Audio/Plug-Ins/HAL and delete the corresponding BlackHole2ch folder.

image.png

By the way, the reason I installed BlackHole2ch was to record system audio during screen recording or live streaming. Today, I suddenly discovered that OBS now directly supports recording system audio.

Here’s how to do it:

  1. Click the add button below the sources and select macOS Screen Capture. SCR-20240525-qcob-2.png

  2. Choose whether to capture desktop audio or application audio based on your needs. image.png

73. [软件] focusee录制系统声音被强制切换为扬声器播放的可能原因和解决方法

Updated:

Focusee 录制系统声音被强制切换为扬声器播放的可能原因和解决方法

在 macOS 上,我想要使用 focusee 录制系统声音的时候我按照它的引导安装了 Gemoo Speaker

虽然输出设备切换到 Gemoo Speaker 输出,这样确实可以录制到系统的声音了,但是是直接用扬声器外放的声音。

后来我发现是我安装了 BlackHole2ch 的原因,卸载掉这个虚拟声卡之后,focusee 就通过 Gemoo Speaker 可以正常地录制到耳机里的声音了。

卸载方法:

/Library/Audio/Plug-Ins/HAL

在这个文件夹中删除 BlackHole2ch 对应的文件夹即可

image.png

顺带一提,当时安装 BlackHole2ch 的原因是想要在录屏或者直播的时候录制到系统的声音,今天我突然发现 obs 已经支持了直接录制系统声音的功能。

具体的操作是:

  1. 点击来源下方的添加按钮,选择 macOS 音频采集 SCR-20240525-qcob-2.png

  2. 根据你的需求选择是采集桌面音频还是应用音频。 image.png

74. [前端] 再次学习History.scrollRestoration

Updated:

再次学习 History.scrollRestoration

2024-05-23-23-52-40

之前在 react.dev 的源代码中了解到了这个 HIstory 的属性,当时写了一篇笔记来记录我对它的理解,现在看来还是一知半解。所以今天打算重新学习一下这个属性,主要从属性以及所属对象的介绍、使用方法,是否开启标准这几个方面来简单展开。

什么是 scrollRestoration

scrollRestoration 是一个属性,它所属的实例是浏览器的 History。

这个属性是做什么的?它用来控制我们在切换历史页面的时候,滚动条的位置会不会恢复到之前的位置。

屏幕录制2024-05-23 10.48.05

如图所示,我们切换历史页面,又切换回最之前的页面,发现滚动条的位置依然保持底部,也就是之前的位置。

什么是切换历史页面,从操作上来讲就是点击浏览器的回退(有的浏览器长按回退键会弹出历史的前面多个页面供选择)、前进按钮

从代码上来讲就是执行下面的这些操作:

history.back()
history.forward()
history.go(page) // page大于0,表示往后面翻对应的页数,反之则是往前翻对应的页数

那么 scrollRestoration 这个属性与是否恢复滚动条的关系是什么?

scrollRestoration 可选的值为 auto 和 manual (如果浏览器支持这个属性,那么它默认是 auto)

scroll restoration mode, a scroll restoration mode, initially “auto”. HTML Standard

如果是 auto:那么在切换历史页面的时候,滚动条会自动地恢复到切换之前的位置。

如果是 manual:那么在切换页面的时候,滚动条会在顶部。

(上述的结果均在未手动修改 state 对应的滚动条位置的情况下)

属性的局限性

我之前觉得这个特性很好,但是为什么要单独地设置一个属性来控制是否要恢复到之前的滚动条位置呢?

History API - 滚动恢复  |  Blog  |  Chrome for Developers 这篇文章中提到:

This often means unsightly jumps as the scroll position changes automatically, and especially so if your app does transitions, or changes the contents of the page in any way. Ultimately this leads to an horrible user experience. To make matters even worse there’s very little you can do about it: Chrome triggers a popState event before the scroll event, which means you can read the current scroll position in popState and then reverse it in the scroll event handler with window.scrollTo (Ewww, but at least it works!). Firefox, however, triggers the scroll event before popState, so you have no idea what the old scroll value was in order to restore it. Bah!

翻译为中文:

这通常意味着当滚动位置自动改变时会出现难看的跳动,尤其是当你的应用程序进行过渡或以任何方式更改页面内容时。这最终会导致糟糕的用户体验。 更糟的是,你几乎无能为力:Chrome 会在 scroll 事件之前触发 popState 事件,这意味着你可以在 popState 中读取当前的滚动位置,然后在 scroll 事件处理程序中使用 window.scrollTo 恢复滚动位置(呃,但至少它能工作!)。然而,Firefox 则是在 popState 事件之前触发 scroll 事件,所以你无法知道旧的滚动位置以便恢复它。唉!

总结一下就是,此文的作者认为这个属性会造成的两个缺点是:

  1. 可能产生不太美观的跳跃:当滚动位置自动改变时,页面内容可能会突然跳动,尤其是在应用程序进行过渡或更改页面内容时,这会导致不好的用户体验。
  2. (在不开启这个属性的时候)非常难以人工地实现恢复滚动位置:由于不同浏览器在触发 popState 和 scroll 事件的顺序上存在差异(如 Chrome 和 Firefox),这使得在所有浏览器中一致地恢复滚动位置变得非常困难。

那么什么时候需要设置为 manual?

参考上面的两个缺点来说,当满足以下的条件的时候,可以考虑设置为 manual

  1. 页面确实会产生了不太美观的跳跃
  2. 不在意历史的滚动条位置,同时更希望全部由手动控制滚动条位置的时候

参考的资料

History: scrollRestoration property - Web APIs | MDN

HTML Standard

75. [AI] ChainForge简单介绍

Updated:

ChainForge 简单介绍

Pasted image 20240417222811

官网:

ChainForge: A visual programming environment for prompt engineering

github 地址:

GitHub - ianarawjo/ChainForge: An open-source visual programming environment for battle-testing prompts to LLMs.

简介

Pasted image 20240417223400

使用场景

评估提示词

攻击性测试

评估模型

评估某项指标

实践

Pasted image 20240417231517

这两个例子单独拿出来讲

TODO

  1. 内部环境运行
  2. 内网环境 proxy [Add Custom Providers - ChainForge Documentation](https://chainforge.ai/docs/custom_providers/ 提供了自定义 llm

参考

使用案例:

X

自动化 Prompts

[2402.10949] The Unreasonable Effectiveness of Eccentric Automatic Prompts

相关的视频

LLM Prompt Injection Attacks & Testing Vulnerabilities With ChainForge - YouTube

使用 ChainForge 进行 LLM 提示注入攻击和漏洞测试

76. [软件] 沉浸式翻译自定义OPENAI接口油猴脚本报错

Updated:

沉浸式翻译自定义 OPENAI 接口油猴脚本报错

2024-05-21-14-49-20

我使用 oneapi 部署了我自己的服务,接入了 deepseek 作为翻译的模型。

但是在配置好之后开启翻译报错:

[!error] This domain is not a part of the @connect list

截图如下:

Pasted image 20240521143947 Pasted image 20240521144007

查询了一下:

@conncet 是油猴脚本一个 tag,作用是允许油猴脚本跨域请求对应的配置的域名

tampermonkey文档

所以油猴脚本报错的解决方法是:

  1. 手动地把对应的域名加上去 Pasted image 20240521143957
  2. 直接添加 // @connect *,这样后续也不会需要新增其他的配置了。
  3. 同理在油猴脚本的设置页面的用户域白名单新增对应的域名或者直接添加* Pasted image 20240521145459
  4. 最后一种简单直接的解决方法是直接使用浏览器插件,我个人的猜测是他们配置了 Match patterns 为<all_urls> Pasted image 20240521144021

77. [生活] 最近的感受-积重难返

Updated:

最近的感受 - 积重难返

23 年年末的时候内转到了做大模型应用的部分,起初是很兴奋和充满动力的。

因为可以一边学习一边做比较前沿的项目,还能白嫖各种大模型厂商的服务。不过这毕竟还是一份工作,公司不可能白养着人而不出成果,所以还是有上上线的压力的。我觉得到这里都是正常的。

但时间久了心里的不适感越来越明显。

首先是一直被诟病的基建,没有 CI/CD,发一次版自动 + 手动的流程结合起来要花上很久的时间,与此同时发布还需要等到 19 点,很多时候不得不为这个原因加班。并且外部服务到内网的代理十分不稳定,极大地降低了工作效率。

其次是心中对于项目的信心越来越不足。项目所使用的框架非常的笨重,不利于拓展,并且有比较严重的性能问题。并且我认为做 agent 最主要的目标是对于某一个领域的问题的结局能力的强弱。但是目前的产品给我的感觉是没有把注意力专注于能力本身,而是开始追求交互。

而且很奇怪的是这并不是一个 local-first 项目,后期是要接数据库的,结果想要我在我临时基于 indexedDB 写的历史记录的基础上更多的需求。

最开始搭后端框架的人的代码也是写的乱七八糟,restful 的出入参定义出现了很多字段不一致的情况,后来只能我自己手动去封装类。在我提出缺少状态码的疑问的时候,说根据 msg 的关键词来判断状态… 这也太硬编码了吧

最后就是对于未来的担忧了,最近约了几次面试,感觉外面确实好卷…但是我只有回家后才有时间学习,再这样下能力差距只会越拖越大。并且涨薪幅度很低,可以说是钱少事多的典范了。

78. 在前端使用abort取消请求

Updated:

在前端使用 abort 取消请求

举个例子,在写 llm 的 chat 的时候,经常会出现需要取消请求的场景。

如何在前端取消请求,涉及到一个接口:AbortController.AbortController() - Web API 接口参考 | MDN

在原生的 js 的写法,参考 mdn 的写法。

let controller
const url = "video.mp4"
const downloadBtn = document.querySelector(".download")
const abortBtn = document.querySelector(".abort")
downloadBtn.addEventListener("click", fetchVideo)
abortBtn.addEventListener("click", () => {
if (controller) {
controller.abort()
controller = null
console.log("Download aborted")
}
})
function fetchVideo() {
controller = new AbortController()
const signal = controller.signal
fetch(url, { signal })
.then((response) => {
console.log("Download complete", response)
})
.catch((err) => {
console.error(`Download error: ${err.message}`)
})
}

在 react 的写法

import React, { useState, useEffect } from "react"
const RequestComponent = () => {
const [responseData, setResponseData] = useState(null)
const [error, setError] = useState(null)
const [loading, setLoading] = useState(false)
const [controller, setController] = useState(null)
useEffect(() => {
// 组件被卸载的时候,取消请求
return () => {
if (controller) {
controller.abort()
}
}
}, [controller])
const fetchData = async () => {
setLoading(true)
setError(null)
const abortController = new AbortController()
setController(abortController)
try {
const response = await fetch("https://api.example.com/data", {
signal: abortController.signal,
})
if (!response.ok) {
throw new Error("Network response was not ok")
}
const data = await response.json()
setResponseData(data)
} catch (error) {
if (error.name === "AbortError") {
console.log("Request canceled by user")
} else {
setError(error)
}
} finally {
setLoading(false)
}
}
const cancelRequest = () => {
if (controller) {
controller.abort()
}
}
return (
<div>
<button onClick={fetchData} disabled={loading}>
{loading ? "Loading..." : "Fetch Data"}
</button>
<button onClick={cancelRequest} disabled={!loading}>
Cancel Request
</button>
{error && <div>Error: {error.message}</div>}
{responseData && <div>Data: {JSON.stringify(responseData)}</div>}
</div>
)
}
export default RequestComponent

在 solidjs 中的写法,可以参考 diu 老师的 GitHub - anse-app/chatgpt-demo: Minimal web UI for ChatGPT.

import { Index, Show, createEffect, createSignal, onCleanup, onMount } from 'solid-js'
import { useThrottleFn } from 'solidjs-use'
import { generateSignature } from '@/utils/auth'
import IconClear from './icons/Clear'
import MessageItem from './MessageItem'
import SystemRoleSettings from './SystemRoleSettings'
import ErrorMessageItem from './ErrorMessageItem'
import type { ChatMessage, ErrorMessage } from '@/types'
export default () => {
const [controller, setController] = createSignal<AbortController>(null)
const requestWithLatestMessage = async() => {
setLoading(true)
setCurrentAssistantMessage('')
setCurrentError(null)
const storagePassword = localStorage.getItem('pass')
try {
const controller = new AbortController()
setController(controller)
const requestMessageList = messageList().slice(-maxHistoryMessages)
if (currentSystemRoleSettings()) {
requestMessageList.unshift({
role: 'system',
content: currentSystemRoleSettings(),
})
}
const timestamp = Date.now()
const response = await fetch('/api/generate', {
method: 'POST',
body: JSON.stringify({
messages: requestMessageList,
time: timestamp,
pass: storagePassword,
sign: await generateSignature({
t: timestamp,
m: requestMessageList?.[requestMessageList.length - 1]?.content || '',
}),
temperature: temperature(),
}),
signal: controller.signal,
})
if (!response.ok) {
const error = await response.json()
console.error(error.error)
setCurrentError(error.error)
throw new Error('Request failed')
}
const data = response.body
if (!data)
throw new Error('No data')
const reader = data.getReader()
const decoder = new TextDecoder('utf-8')
let done = false
while (!done) {
const { value, done: readerDone } = await reader.read()
if (value) {
const char = decoder.decode(value)
if (char === '\n' && currentAssistantMessage().endsWith('\n'))
continue
if (char)
setCurrentAssistantMessage(currentAssistantMessage() + char)
isStick() && instantToBottom()
}
done = readerDone
}
} catch (e) {
console.error(e)
setLoading(false)
setController(null)
return
}
archiveCurrentMessage()
isStick() && instantToBottom()
}
const stopStreamFetch = () => {
if (controller()) {
controller().abort()
...
}
}
return (
...
)
}

79. [前端] open graph 简述

Updated:

Open Graph 简述

场景

在我们使用 twitter 的时候,会发现有的链接会显示预览卡片,有的不会。

Pasted image 20240409203435 Pasted image 20240409204440

这是因为有的网站设置了 open graph,有的没有。

Pasted image 20240409103122

那么什么是 open graph?

open graph 是一个由 facebook 在 2010 年发布的协议,用于在社交网络上分享链接时,显示预览卡片。

Pasted image 20240409204654

我觉得无论是它的名称还是意图,都能看出 facebook 以及其他支持这种协议的社交平台的开放性, 特别是在某些平台会屏蔽外链或者限流带有外链的衬托下。

Pasted image 20240409205145

和 open graph 类似还有 twitter 自己的 card,如果 twitter card 和 open graph 同时存在的话,会先显示在 twitter card。如果 twitter card 没有定义,才会显示 open graph。

Pasted image 20240409213244 Pasted image 20240408163056

预览和检查工具

OpenGraph - Preview Social Media Share and Generate Metatags - OpenGraph

Pasted image 20240409201933

OpenGraph - Preview Images and Generate Open Graph Meta Tags

Pasted image 20240409195616 Pasted image 20240409131420

一些例子

Open Graph Examples

Pasted image 20240409131603

80. [前端] open-graph intro

Updated:

Open-graph Intro

open graph 简述

Scenario

When we use Twitter, we notice that some links display preview cards while others do not.

Pasted image 20240409203435 Pasted image 20240409204440

This is because some websites have set up Open Graph, while others have not.

Pasted image 20240409103122

What is Open Graph?

Open Graph is a protocol introduced by Facebook in 2010, used for displaying preview cards when sharing links on social networks.

Pasted image 20240409204654

From its name and purpose, it’s evident that Open Graph signifies the openness of Facebook and other platforms supporting this protocol, especially amidst certain platforms that block external links or throttle those containing external links.

Pasted image 20240409205145

Similar to Open Graph, Twitter has its own card system. If both Twitter Card and Open Graph coexist, Twitter Card takes precedence. Only if Twitter Card is not defined, Open Graph is displayed.

Pasted image 20240409213244 Pasted image 20240408163056

Preview and Inspection Tools

OpenGraph - Preview Social Media Share and Generate Metatags - OpenGraph

Pasted image 20240409201933

OpenGraph - Preview Images and Generate Open Graph Meta Tags

Pasted image 20240409195616 Pasted image 20240409131420

Some Examples

Open Graph Examples

Pasted image 20240409131603