In today's data-driven world, having a personal AI assistant that is both secure and efficient is becoming increasingly valuable. This article provides a detailed guide on how to deploy Deepseek locally, enabling you to leverage its capabilities for intelligent knowledge management.
Before diving into the deployment process, ensure your system meets the following minimum requirements
Ollama is a powerful tool that allows you to run large language models locally. Here's how to install and configure it on different operating systems:
macOS:
Windows:
Linux (Ubuntu/Debian):
curl -fsSL https://ollama.com/install.sh | sudo bash
sudo usermod -aG ollama $USER # Add user permissions
sudo systemctl start ollama # Start the service
To ensure Ollama is installed correctly, run the following command in your terminal:
ollama -v
If the output displays "ollama version is 0.5.7"
or a similar version number, the installation was successful. You can also verify by visiting http://localhost:11434/
in your browser.
For this guide, we will use the Deepseek r1 model as an example.
ollama run deepseek-r1
This command initiate the pulling of the manifest and the necessary layers. Example output during the pulling process:
pulling manifest
pulling 96c415656d37... 100% ▕██████████████▏ 4.7 GB
pulling 369ca498f347... 100% ▕██████████████▏ 387 B
pulling 6e4c38e1172f... 100% ▕██████████████▏ 1.1 KB
pulling f4d24e9138dd... 100% ▕██████████████▏ 148 B
pulling 40fb844194b2... 100% ▕██████████████▏ 487 B
verifying sha256 digest
writing manifest
success
Once the installation is complete, you'll see the following prompt, indicating that the model is ready for dialogue:
>>> Send a message (/? for help)
Running Ollama will show a background process, which may appear in the Mac menu bar or the Windows taskbar.
Test the model using an interactive dialogue. For example, ask it to write a quicksort algorithm in Python:
Please write a quicksort algorithm in Python
If the model outputs the complete code, it has been successfully loaded and is working correctly.
To improve user experience, use a Chat UI
http://127.0.0.1:11434
.The Page Assist browser plugin allows for convenient interaction with the model directly from your browser.
This plugin also supports local knowledge base construction.
Dify is an open-source LLM application development platform. To build a knowledge base with Dify:
Clone Source Code:
Clone Dify's repository from GitHub.
Prepare the environment:
cp .env.example .env
Start Docker Containers: Docker is required
docker compose up -d
docker-compose up -d
Ensure all containers are running without errors.
http://localhost/
(default port 80).http://localhost:11434
faces access problems, try http://host.docker.internal:11434
.Here’s an example of using Deepseek for translating internationalization configuration files.
File Format: The configuration file is in JSON format, with string values to be translated, for example zh.json:
{
"window": {
"willUnload": {
"title": "确认刷新当前页面吗?",
"message": "系统可能不会保存您做的更改",
"unload_bt": "重新加载",
"cancel_bt": "取消"
}
}
}
Translation Script: Use a script like trans.js
to automate the translation:
const fs = require("fs");
const axios = require("axios");
// 1. Read the local JSON file
const readJsonFile = (filePath) => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, "utf8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(JSON.parse(data));
}
});
});
};
const MODEL = "deepseek-r1:14b";
// 2. Call the local large model interface for translation
const translateText = async (text, key) => {
let response;
try {
console.time(`run worker ${key}`);
response = await axios.post("http://localhost:11434/api/generate", {
// model: 'deepseek-r1:7b',
model: MODEL,
prompt: `There is a partially internationalized configuration file for the client, and the content is in json format, which needs to be translated. The translation is required to be carried out in steps:
1. Translate Chinese into English
2. Keep the original json format unchanged and replace the value with the translated text
3. You always respond in legal JSON format, and the return result format is as follows: {"key1":"translated text 1","key2":"translated text 2"}, return the result directly, without symbol wrapping Configuration file """${JSON.stringify(text)}"""`,
stream: false,
});
console.timeEnd(`run worker ${key}`);
const splitText = "";
const startIndex = response.data.response.indexOf(splitText);
const result = response.data.response
.slice(startIndex + splitText.length)
.trim()
.replace(/<<+|>>+/g, "");
// console.log('response.data.response:', response.data.response, JSON.parse(result), result)
return JSON.parse(result); // Assuming the translation result returned by the interface is in response.data.translatedText
} catch (error) {
console.error("Translation error:", key);
return translateText(text, key); // Return the original text if the translation fails
}
};
// 3. Parallel translation logic (manually control concurrency)
const translateJson = async (jsonData, concurrency = 5) => {
const entries = Object.entries(jsonData);
const translatedData = {};
let currentIndex = 0; // Index of the currently processed task
// Define a worker thread: each thread continuously processes the next task
const worker = async () => {
while (currentIndex < entries.length) {
const index = currentIndex++;
if (index >= entries.length) break; // All tasks have been completed
const [key, value] = entries[index];
try {
translatedData[key] = await translateText(value, key);
} catch (error) {
translatedData[key] = value; // Keep the original text
}
}
};
// Start the specified number of worker threads
const workers = Array(concurrency).fill(null).map(worker);
await Promise.all(workers); // Wait for all threads to complete
const result = {};
// Keep the original order
entries.forEach(([key, value]) => {
result[key] = translatedData[key] || value;
});
return result;
};
// 4. Generate a new file with the translated content
const writeTranslatedJson = (filePath, data) => {
return new Promise((resolve, reject) => {
fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf8", (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
};
function compareObjectsWithPath(obj1, obj2, path = "") {
// Returns the path directly when the types are different
if (typeof obj1 !== typeof obj2) {
return { success: false, path: path || "root" };
}
// Handle enumerable objects (objects or arrays)
if (typeof obj1 === "object" && obj1 !== null && obj2 !== null) {
const isArr1 = Array.isArray(obj1);
const isArr2 = Array.isArray(obj2);
// Array types are inconsistent
if (isArr1 !== isArr2) {
return { success: false, path: path || "root" };
}
if (isArr1) {
// Array length is different
if (obj1.length !== obj2.length) {
return { success: false, path: path || "root" };
}
// Recursively check array elements
for (let i = 0; i < obj1.length; i++) {
const currentPath = `${path}[${i}]`;
const result = compareObjectsWithPath(obj1[i], obj2[i], currentPath);
if (!result.success) return result;
}
return { success: true };
} else {
// Check if it is a pure object (literal object)
const isPlainObj1 = isPlainObject(obj1);
const isPlainObj2 = isPlainObject(obj2);
if (isPlainObj1 !== isPlainObj2) {
return { success: false, path: path || "root" };
}
// Non-pure objects (such as Date, RegExp) need to check if they are all strings
if (!isPlainObj1) {
return typeof obj1 === "string" && typeof obj2 === "string"
? { success: true }
: { success: false, path: path || "root" };
}
// Merge all keys and check the number
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
const allKeys = new Set([...keys1, ...keys2]);
if (
allKeys.size !== keys1.length ||
allKeys.size !== keys2.length
) {
return { success: false, path: path || "root" };
}
// Recursively check each property
for (const key of allKeys) {
const currentPath = path ? `${path}.${key}` : key;
if (!keys1.includes(key) || !keys2.includes(key)) {
return { success: false, path: currentPath };
}
const result = compareObjectsWithPath(
obj1[key],
obj2[key],
currentPath
);
if (!result.success) return result;
}
return { success: true };
}
} else {
// Basic types: check if they are all strings
return typeof obj1 === "string" && typeof obj2 === "string"
? { success: true }
: { success: false, path: path || "root" };
}
}
// Determine whether it is a pure object (literal object)
function isPlainObject(value) {
return Object.prototype.toString.call(value) === "[object Object]";
}
// Main function
const main = async () => {
console.time("run main");
const inputFilePath = "./locales/zh.json"; // Input JSON file path
const outputFilePath = `output_${MODEL}.json`; // Output JSON file path
try {
// Read JSON file
const jsonData = await readJsonFile(inputFilePath);
// Translate JSON content
const translatedData = await translateJson(jsonData);
// Write the translated content to a new file
await writeTranslatedJson(outputFilePath, translatedData);
console.log(
"Translation completed, whether there are omissions in the result:",
compareObjectsWithPath(jsonData, translatedData)
);
console.log("Translation completed, the result has been written to:", outputFilePath);
} catch (error) {
console.error("Error occurred during processing:", error);
}
console.timeEnd("run main");
};
// Execute the main function
main();
Execution: Run the script with Node.js:
node trans.js
Result: The translated JSON file will be saved as output_deepseek-r1:7b.json or output_deepseek-r1:14b.json.
Based on the test, the 14b model is more accurate and has a higher one-time translation success rate compared to the 7b model.
Here's the translation result:
"window": {
"willUnload": {
"title": "What should you confirm before refreshing the current page?",
"message": "the system might not save your changes",
"unload_bt": "Reload",
"cancel_bt": "Cancel"
}
}
By following these steps, you can successfully deploy Deepseek locally and create a personal knowledge base application. Enjoy the benefits of having your own secure, efficient, and intelligent AI assistant!