Ubuntu部署ktransformers
准备工作
一台服务器
CPU:500G
GPU:48G(NVIDIA4090)
系统:Ubuntu20.04(github的文档好像用的是22.04)
第一步:下载权重文件
1.下载hfd
wget https://hf-mirror.com/hfd/hfd.sh
chmod a+x hfd.sh
2.设置环境变量
export HF_ENDPOINT=https://hf-mirror.com
3.下载模型(需要梯子,需要带上huggingface的token)
./hfd.sh gpt2
4.下载数据集(需要梯子,需要带上huggingface的token)
./hfd.sh wikitext --dataset
5.下载大文件(需要梯子,文件很大,大约四五百G)
./hfd.sh unsloth/DeepSeek-R1-GGUF --include DeepSeek-R1-Q4_K_M/*
第二步:拉代码,编译代码
1.使用Anaconda3安装Python3.11
conda create --name ktransformers python=3.11
conda activate ktransformers
conda install -c conda-forge libstdcxx-ng
2.安装其他依赖
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip3 install packaging ninja cpufeature numpy
sudo add-apt-repository ppa: ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install --only-upgrade libstdc++6
pip install flash-attn --no-build-isolation
3.查看显卡版本及cuda版本
以下两条指令显示的CUDA版本需要一致,若不一致,系统会以nvcc --version的为准
nvcc --version
nvidia-smi

4.拉代码
git clone https://github.com/kvcache-ai/ktransformers.git
cd ktransformers
git submodule init
git submodule update
5.编译
export USE_NUMA=1
make dev_install

第三部:运行
python ktransformers/local_chat.py --model_path deepseek-ai/DeepSeek-R1 --gguf_path /home/dpkj/deepseek/DeepSeek-R1-GGUF/DeepSeek-R1-Q4_K_M/ --cpu_infer 50 --cache_lens 1536 --max_new_tokens 8192
# --model_path:模型位置,不需要修改
# --gguf_path:前面下载的大文件,模型文件位置,按照实际情况而定
# --cpu_infer:CPU占用,单位百分比,如果服务器不死DDR5双路CPU,可以适量调低此占比
其他启动参数
python -m transformers.local_chat --model_path deepseek-ai/DeepSeek-R1 --gguf_path /root/DeepSeek-R1-GGUF/DeepSeek-R1-Q4_K_M/ --cpu_infer 53 --cache_lens 1536
python ./transformers/local_chat.py --model_path deepseek-ai/DeepSeek-R1 --gguf_path /home/shadeform/DeepSeek-R1-GGUF/DeepSeek-R1-Q4 K M/ --cpu_infer 53 --cache_lens 1536 --optimize_config_path transformers/optimize/optimize_rules/DeepSeek-V3-Chat-multi-gpu-marlin.yaml
python -m transformers.local_chat --model_path deepseek-ai/DeepSeek-R1 --gguf_path /root/autodi-tmp/DeepSeek-R1-GGUF/DeepSeek-R1-Q4 K M/ --cpu_infer 128 --cache_lens 1536 --max_new_tokens 8192 --optimize_config_path ./transformers/optimize/optimize_rules/DeepSeek-V3-Chat-multi-gpu-marlin-4.yaml
transformers --model_path deepseek-ai/DeepSeek-R1 --gguf_path /root/autodi-tmp/DeepSeek-R1-GGUF/DeepSeek-R1-Q4 K M/ --cpu_infer 65 --cache_lens 1536 --max_new_tokens 8192 --port 6006 --optimize_config_path /transformers/optimize/optimize_rules/DeepSeek-V3-Chat-multi-gpu-marlin-4.yaml
curl -X 'POST"
"http://localhost:6006/v1/chat/completions'\
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d'{
"messages": [
"content": "tell a joke",
"role": "user"
],
"model": "ktranformers-model",
"stream": true
}'
外传
1. 使用API方式调用
新建文件:chat_openai.py
import argparse
import uvicorn
from typing import List, Dict, Optional, Any
from fastapi import FastAPI, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import os
import sys
import time
from fastapi import Request
from fastapi.responses import StreamingResponse, JSONResponse
import json
import logging# 设置日志记录
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)project_dir = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, project_dir)
import torch
from transformers import (
AutoTokenizer,
AutoConfig,
AutoModelForCausalLM,
GenerationConfig,
TextStreamer,
)
from ktransformers.optimize.optimize import optimize_and_load_gguf
from ktransformers.models.modeling_deepseek import DeepseekV2ForCausalLM
from ktransformers.models.modeling_qwen2_moe import Qwen2MoeForCausalLM
from ktransformers.models.modeling_deepseek_v3 import DeepseekV3ForCausalLM
from ktransformers.models.modeling_llama import LlamaForCausalLM
from ktransformers.models.modeling_mixtral import MixtralForCausalLM
from ktransformers.util.utils import prefill_and_generate
from ktransformers.server.config.config import Configcustom_models = {
"DeepseekV2ForCausalLM": DeepseekV2ForCausalLM,
"DeepseekV3ForCausalLM": DeepseekV3ForCausalLM,
"Qwen2MoeForCausalLM": Qwen2MoeForCausalLM,
"LlamaForCausalLM": LlamaForCausalLM,
"MixtralForCausalLM": MixtralForCausalLM,
}ktransformer_rules_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "optimize", "optimize_rules")
default_optimize_rules = {
"DeepseekV2ForCausalLM": os.path.join(ktransformer_rules_dir, "DeepSeek-V2-Chat.yaml"),
"DeepseekV3ForCausalLM": os.path.join(ktransformer_rules_dir, "DeepSeek-V3-Chat.yaml"),
"Qwen2MoeForCausalLM": os.path.join(ktransformer_rules_dir, "Qwen2-57B-A14B-Instruct.yaml"),
"LlamaForCausalLM": os.path.join(ktransformer_rules_dir, "Internlm2_5-7b-Chat-1m.yaml"),
"MixtralForCausalLM": os.path.join(ktransformer_rules_dir, "Mixtral.yaml"),
}# 全局变量,存储初始化后的模型
chat_model = Noneclass OpenAIChat:
def __init__(
self,
model_path: str,
optimize_rule_path: str = None,
gguf_path: str = None,
cpu_infer: int = Config().cpu_infer,
use_cuda_graph: bool = True,
mode: str = "normal",
):
torch.set_grad_enabled(False)
Config().cpu_infer = cpu_inferself.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
config = AutoConfig.from_pretrained(model_path, trust_remote_code=True)
self.streamer = TextStreamer(self.tokenizer, skip_prompt=True) if not Config().cpu_infer else None
if mode == 'long_context':
assert config.architectures[0] == "LlamaForCausalLM", "Only LlamaForCausalLM supports long_context mode"
torch.set_default_dtype(torch.float16)
else:
torch.set_default_dtype(config.torch_dtype)with torch.device("meta"):
if config.architectures[0] in custom_models:
if "Qwen2Moe" in config.architectures[0]:
config._attn_implementation = "flash_attention_2"
if "Llama" in config.architectures[0]:
config._attn_implementation = "eager"
if "Mixtral" in config.architectures[0]:
config._attn_implementation = "flash_attention_2"
model = custom_models[config.architectures[0]](config)
else:
model = AutoModelForCausalLM.from_config(
config, trust_remote_code=True, attn_implementation="flash_attention_2"
)if optimize_rule_path is None:
if config.architectures[0] in default_optimize_rules:
optimize_rule_path = default_optimize_rules[config.architectures[0]]optimize_and_load_gguf(model, optimize_rule_path, gguf_path, config)
try:
model.generation_config = GenerationConfig.from_pretrained(model_path)
except:
model.generation_config = GenerationConfig(
max_length=128,
temperature=0.7,
top_p=0.9,
do_sample=True
)
if model.generation_config.pad_token_id is None:
model.generation_config.pad_token_id = model.generation_config.eos_token_id
model.eval()
self.model = model
self.use_cuda_graph = use_cuda_graph
self.mode = mode
logger.info("Model loaded successfully!")def create_chat_completion(
self,
messages: List[Dict[str, str]],
temperature: float = 0.7,
max_tokens: int = 1000,
top_p: float = 0.9,
force_think: bool = False,
) -> Dict:
input_tensor = self.tokenizer.apply_chat_template(
messages, add_generation_prompt=True, return_tensors="pt"
)
if force_think:
token_thinks = torch.tensor([self.tokenizer.encode("<think>\\n", add_special_tokens=False)],
device=input_tensor.device)
input_tensor = torch.cat([input_tensor, token_thinks], dim=1)generation_config = GenerationConfig(
temperature=temperature,
top_p=top_p,
max_new_tokens=max_tokens,
do_sample=True # Ensure do_sample is True if using temperature or top_p
)generated = prefill_and_generate(
self.model,
self.tokenizer,
input_tensor.cuda(),
max_tokens,
self.use_cuda_graph,
self.mode,
force_think
)# Convert token IDs to text
generated_text = self.tokenizer.decode(generated, skip_special_tokens=True)return {
"choices": [{
"message": {
"role": "assistant",
"content": generated_text
}
}],
"usage": {
"prompt_tokens": input_tensor.shape[1],
"completion_tokens": len(generated),
"total_tokens": input_tensor.shape[1] + len(generated)
}
}class ChatMessage(BaseModel):
role: str
content: strclass ChatCompletionRequest(BaseModel):
messages: List[ChatMessage] # 确保 messages 是 Pydantic 模型实例的列表
model: str = "default-model"
temperature: Optional[float] = 0.7
top_p: Optional[float] = 0.9
max_tokens: Optional[int] = 1000
stream: Optional[bool] = False
force_think: Optional[bool] = Trueclass ChatCompletionResponse(BaseModel):
id: str = "chatcmpl-default"
object: str = "chat.completion"
created: int = 0
model: str = "default-model"
choices: List[Dict[str, Any]]
usage: Dict[str, int]app = FastAPI(title="KVCache.AI API Server")
@app.get("/health")
async def health_check():
return {"status": "healthy"}@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = f"{process_time:.4f}s"
return responseapp.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)@app.post("/v1/chat/completions", response_model=ChatCompletionResponse)
async def chat_completion(request: ChatCompletionRequest):
try:
# 如果 messages 是 Pydantic 模型实例列表,使用 model_dump
messages = [m.model_dump() for m in request.messages]
response = chat_model.create_chat_completion(
messages=messages,
temperature=request.temperature,
max_tokens=request.max_tokens,
top_p=request.top_p,
force_think=request.force_think
)return {
"id": f"chatcmpl-{int(time.time())}",
"object": "chat.completion",
"created": int(time.time()),
"model": request.model,
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": response['choices'][0]['message']['content']
},
"finish_reason": "stop"
}],
"usage": response['usage']
}
except Exception as e:
logger.error(f"API Error: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Internal server error: {str(e)}"
)def create_app(model_path: str, gguf_path: str, cpu_infer:int, optimize_rule_path: Optional[str] = None):
global chat_model
chat_model = OpenAIChat(
model_path=model_path,
gguf_path=gguf_path,
optimize_rule_path=optimize_rule_path,
cpu_infer=cpu_infer
)
return appdef main():
parser = argparse.ArgumentParser(description="KVCache.AI API Server")
parser.add_argument("--model_path", type=str, required=True, help="HuggingFace模型路径")
parser.add_argument("--gguf_path", type=str, required=True, help="GGUF模型文件路径")
parser.add_argument("--optimize_rule_path", type=str, help="优化规则文件路径")
parser.add_argument("--port", type=int, default=8000, help="服务端口号")
parser.add_argument("--cpu_infer", type=int, default=10, help="使用cpu数量")
parser.add_argument("--host", type=str, default="0.0.0.0", help="绑定地址")
args = parser.parse_args()create_app(
model_path=args.model_path,
gguf_path=args.gguf_path,
optimize_rule_path=args.optimize_rule_path,
cpu_infer=args.cpu_infer
)uvicorn.run(
app,
host=args.host,
port=args.port,
loop="uvloop",
http="httptools",
timeout_keep_alive=300,
log_level="info",
access_log=False
)if __name__ == "__main__":
main()
文件防止位置:

安装依赖:
pip install protobuf uvicorn httptools
pip install uvloop
启动:
python ktransformers/chat_openai.py --model_path deepseek-ai/DeepSeek-R1 --gguf_path /home/dpkj/deepseek/DeepSeek-R1-GGUF/DeepSeek-R1-Q4_K_M/

2.使用open-WEBUI进行可视化对接
# 使用Pip下载OPEN-WEBUI
pip install open-webui# 下载完成后开启服务open-webui serve
import os
import json
import requests
from pydantic import BaseModel, Field
from typing import List, Union, Iterator# Set DEBUG to True to enable detailed logging
DEBUG = False
class Pipe:
class Valves(BaseModel):
openai_API_KEY: str = Field(default="none") # Optional API key if needed
DEFAULT_MODEL: str = Field(default="DeepSeek-R1") # Default model identifierdef __init__(self):
self.id = "DeepSeek-R1"
self.type = "manifold"
self.name = "KT: "
self.valves = self.Valves(
**{
"openai_API_KEY": os.getenv("openai_API_KEY", "none"),
"DEFAULT_MODEL": os.getenv("openai_DEFAULT_MODEL", "DeepSeek-R1"),
}
)
# Self-hosted FastAPI server details
self.api_url = (
"http://localhost:8000/v1/chat/completions" # FastAPI server endpoint
)
self.headers = {"Content-Type": "application/json"}def get_openai_models(self):
"""Return available models - for openai we'll return a fixed list"""
return [{"id": "KT", "name": "DeepSeek-R1"}]def pipes(self) -> List[dict]:
return self.get_openai_models()def pipe(self, body: dict) -> Union[str, Iterator[str]]:
try:
# Use default model ID since OpenAI has a single endpoint
model_id = self.valves.DEFAULT_MODEL
messages = []# Process messages including system, user, and assistant messages
for message in body["messages"]:
if isinstance(message.get("content"), list):
# For OpenAI, we'll join multiple content parts into a single text
text_parts = []
for content in message["content"]:
if content["type"] == "text":
text_parts.append(content["text"])
elif content["type"] == "image_url":
# OpenAI might not support image inputs - add a note about the image
text_parts.append(f"[Image: {content['image_url']['url']}]")
messages.append(
{"role": message["role"], "content": "".join(text_parts)}
)
else:
# Handle simple text messages
messages.append(
{"role": message["role"], "content": message["content"]}
)if DEBUG:
print("FastAPI API request:")
print(" Model:", model_id)
print(" Messages:", json.dumps(messages, indent=2))# Prepare the API call parameters
payload = {
"model": model_id,
"messages": messages,
"temperature": body.get("temperature", 0.7),
"top_p": body.get("top_p", 0.9),
"max_tokens": body.get("max_tokens", 8192),
"stream": body.get("stream", True),
}# Add stop sequences if provided
if body.get("stop"):
payload["stop"] = body["stop"]# Sending request to local FastAPI server
if body.get("stream", False):
# Streaming response
def stream_generator():
try:
response = requests.post(
self.api_url,
json=payload,
headers=self.headers,
stream=True,
)
for line in response.iter_lines():
if line:
yield line.decode("utf-8")
except Exception as e:
if DEBUG:
print(f"Streaming error: {e}")
yield f"Error during streaming: {str(e)}"return stream_generator()
else:
# Regular response
response = requests.post(
self.api_url, json=payload, headers=self.headers
)
if response.status_code == 200:
generated_content = (
response.json()
.get("choices", [{}])[0]
.get("message", {})
.get("content", "")
)
return generated_content
else:
return f"Error: {response.status_code}, {response.text}"
except Exception as e:
if DEBUG:
print(f"Error in pipe method: {e}")
return f"Error: {e}"def health_check(self) -> bool:
"""Check if the OpenAI API (local FastAPI service) is accessible"""
try:
# Simple health check with a basic prompt
response = requests.post(
self.api_url,
json={
"model": self.valves.DEFAULT_MODEL,
"messages": [{"role": "user", "content": "Hello"}],
"max_tokens": 5,
},
headers=self.headers,
)
return response.status_code == 200
except Exception as e:
if DEBUG:
print(f"Health check failed: {e}")
return False
相关文章:
Ubuntu部署ktransformers
准备工作 一台服务器 CPU:500G GPU:48G(NVIDIA4090) 系统:Ubuntu20.04(github的文档好像用的是22.04) 第一步:下载权重文件 1.下载hfd wget https://hf-mirror.com/hfd/hfd.s…...
助力DeepSeek私有化部署服务:让企业AI落地更简单、更安全
在数字化转型的浪潮中,越来越多的企业选择私有化部署AI技术,以保障数据安全、提升业务效率并实现自主可控。DeepSeek作为行业领先的AI开源技术,其技术可以支持企业私有化部署,企业需要一站式服务私有化部署,涵盖硬件采…...
面试官询问项目前后端人员配比之高分示范回答
面试官询问项目前后端人员配比之高分示范回答 以下是对两个项目前后端人员配置的精准分析,结合 技术复杂度、协作效率、风险控制 三个维度设计回答,突出合理性与团队协作意识: 一、《x能x服》项目(Vue重构) 1. 人员配置与分工 前端:1人(独立开发) 负责旧系统业务逻辑…...
MyBatis中的日志和映射器说明
1.MyBatis中的日志 1.1 什么是日志 在我们编写应用的时候,有一些信息需要及时查看,查看的时候有时需要输出到控制台,有时需要输出到文件。MyBatis也需要日志,一般情况下,使用log4j进行日志管理。 1.2 在MyBatis中…...
深入了解 Pinia:Vue 的下一代状态管理工具 (上篇)
引言 在现代前端开发中,状态管理是构建复杂应用的关键。Vue 生态系统中,Vuex 一直是官方推荐的状态管理工具。然而,随着 Vue 3 的发布,一个新的状态管理工具——Pinia,逐渐崭露头角。Pinia 不仅继承了 Vuex 的优点&am…...
Unity 中导入的VRM模型渲染为VRoid风格
按照前篇Unity VRoidBlenderUnity 3D人物模型导入使用-CSDN博客 导入到Unity之后,可以按需调整模型在场景中的渲染表现, 但是按照教程中完成的情况, 整个模型没有进行材质区分, 仅用一个材质表现整个模型, 导致不能给不同部位进行渲染调整. 这里我希望能够在Unity中获得跟VRoi…...
【ELK】【Elasticsearch 】DSL 和 DQL
1. DSL 查询(Query DSL) 全称:Domain Specific Language(领域特定语言)。 定义:Elasticsearch 提供的一种基于 JSON 的查询语言,用于构建复杂的查询逻辑。 特点: 支持多种查询类型…...
最新版本Exoplayer扩展FFmpeg音频软解码保姆级教程
ExoPlayer 是一个开源的 Android 媒体播放库,由 Google 开发和维护,用于替代 Android 系统自带的 MediaPlayer。它提供了更强大的功能、更好的性能和更高的灵活性,适用于各种复杂的媒体播放场景。所以被广泛用于各种播放器场景。 最近项目中…...
面对低消费欲人群,我们如何开发其需求?
在市场增量放缓的当下,开发深度开发各层次的人群已经成为现实需求。低消费欲人群并非“没有需求”,而是更谨慎、更理性。他们可能对价格敏感,但对实用性、情感共鸣和生活品质的追求依然存在。就让我们从以下四个角度,拆解如何激发…...
《算法基础入门:最常用的算法详解与应用(持续更新实战与面试题)》
1. 排序算法 排序算法是将一组数据按特定的顺序排列起来的算法,常见的有: 冒泡排序(Bubble Sort)选择排序(Selection Sort)插入排序(Insertion Sort)归并排序(Merge So…...
Linux设备驱动-练习
练习要求: 一、设备树 1、配置设备树信息:将3个led灯和1个风扇使用到的设备信息配置到设备树中 二、设备驱动层 1、通过of_find_node_by_name、of_get_named_gpion等内核核心层统一的api接口调用外设; 2、通过udev设备管理器自动注册并创建设…...
蓝桥杯核心内容
核心内容 数学 质数与筛质数,分解质因数 分解质因数 所有的数都可以写成有限个数相乘质数:可以写成1✖本身(如131✖13)合数:ab1✖...✖bn-》把乘数里面是合数的再分(如b3是合数-》b3c1✖c2)进…...
Spring Boot拦截器(Interceptor)详解
拦截器Interceptor 拦截器我们主要分为三个方面进行讲解: 介绍下什么是拦截器,并通过快速入门程序上手拦截器拦截器的使用细节通过拦截器Interceptor完成登录校验功能 1. 快速入门 什么是拦截器? 是一种动态拦截方法调用的机制ÿ…...
非常好用的ssh工具Xterminal
免安装 Xterminal - 更好用的开发工具,但不止于(SSH/控制台/More)...
【Python项目】基于Django的医疗领域用户问答意图识别系统
【Python项目】基于Django的医疗领域用户问答意图识别系统 技术简介:采用Python技术、MySQL数据库、Neo4j图形数据库、Django框架、BERTLSTMCRF模型等技术实现。 系统简介: 医疗领域用户问答意图识别系统是一个基于知识图谱的智能问答平台,旨…...
深入理解指针(六)
一、字符指针变量 1.1字符指针变量 在指针的类型中我们知道有一种指针类型为字符指针char* 一般有以下两种使用方式: #include<stdio.h> int main() { char ch w; char* pc &ch; *pc w; return 0; } #include<stdio.h> int main()…...
Linux下基本指令(4)
Linux权限的概念 Linux下有两种用户:超级用户(root)、普通用户。 超级用户:可以再linux系统下做任何事情,不受限制 普通用户:在linux下做有限的事情。 超级用户的命令提示符是“#”,普通用户…...
vue 手写分页
【先看效果】 (1)内容小于2页 不展示页码 (2)1 < 内容页数< 限定展示页码 展示:页码、上下页;隐藏:首页、末页图标,上、下一区间码。即:(页数&#…...
Spring Boot项目接收前端参数的11种方式
大家好,我是。在前后端项目交互中,前端传递的数据可以通过HTTP请求发送到后端, 后端在Spring Boot中如何接收各种复杂的前端数据呢?这篇文章总结了11种在Spring Boot中接收前端数据的方式。 1 搭建项目 1.通过Spring Initializr…...
Springboot项目:使用MockMvc测试get和post接口(含单个和多个请求参数场景)
一、引入MockMvc依赖 使用MockMvc,必须要引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>二、具体演示…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...


