Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
- **Easy Navigation**: Simple, intuitive interface to explore the wiki
- **Ask Feature**: Chat with your repository using RAG-powered AI to get accurate answers
- **DeepResearch**: Multi-turn research process that thoroughly investigates complex topics
- **Multiple Model Providers**: Support for Google Gemini, OpenAI, OpenRouter, and local Ollama models
- **Flexible Embeddings**: Choose between OpenAI, Google AI, or local Ollama embeddings for optimal performance
- **Multiple Model Providers**: Support for Google Gemini, OpenAI, ZhipuAI GLM-4, OpenRouter, and local Ollama models
- **Flexible Embeddings**: Choose between OpenAI, Google AI, ZhipuAI, or local Ollama embeddings for optimal performance

## 🚀 Quick Start (Super Easy!)

Expand All @@ -42,6 +42,8 @@ echo "GOOGLE_API_KEY=your_google_api_key" > .env
echo "OPENAI_API_KEY=your_openai_api_key" >> .env
# Optional: Use Google AI embeddings instead of OpenAI (recommended if using Google models)
echo "DEEPWIKI_EMBEDDER_TYPE=google" >> .env
# Optional: Add ZhipuAI API key if you want to use GLM-4 models
echo "ZHIPUAI_API_KEY=your_zhipuai_api_key" >> .env
# Optional: Add OpenRouter API key if you want to use OpenRouter models
echo "OPENROUTER_API_KEY=your_openrouter_api_key" >> .env
# Optional: Add Ollama host if not local. defaults to http://localhost:11434
Expand All @@ -59,6 +61,7 @@ For detailed instructions on using DeepWiki with Ollama and Docker, see [Ollama
> 💡 **Where to get these keys:**
> - Get a Google API key from [Google AI Studio](https://makersuite.google.com/app/apikey)
> - Get an OpenAI API key from [OpenAI Platform](https://platform.openai.com/api-keys)
> - Get a ZhipuAI API key from [ZhipuAI Platform](https://open.bigmodel.cn/)
> - Get Azure OpenAI credentials from [Azure Portal](https://portal.azure.com/) - create an Azure OpenAI resource and get the API key, endpoint, and API version

### Option 2: Manual Setup (Recommended)
Expand All @@ -72,6 +75,10 @@ GOOGLE_API_KEY=your_google_api_key
OPENAI_API_KEY=your_openai_api_key
# Optional: Use Google AI embeddings (recommended if using Google models)
DEEPWIKI_EMBEDDER_TYPE=google
# Optional: Add this if you want to use ZhipuAI GLM-4 models
ZHIPUAI_API_KEY=your_zhipuai_api_key
# Optional: Use ZhipuAI embeddings (recommended for Chinese repositories)
# DEEPWIKI_EMBEDDER_TYPE=zhipuai
# Optional: Add this if you want to use OpenRouter models
OPENROUTER_API_KEY=your_openrouter_api_key
# Optional: Add this if you want to use Azure OpenAI models
Expand Down
21 changes: 17 additions & 4 deletions api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ This is the backend API for DeepWiki, providing smart code analysis and AI-power

## ✨ Features

- **Streaming AI Responses**: Real-time responses using Google's Generative AI (Gemini)
- **Multiple AI Providers**: Support for Google Gemini, OpenAI, ZhipuAI GLM-4, OpenRouter, AWS Bedrock, and Ollama
- **Streaming AI Responses**: Real-time responses with streaming generation
- **Smart Code Analysis**: Automatically analyzes GitHub repositories
- **RAG Implementation**: Retrieval Augmented Generation for context-aware responses
- **Flexible Embeddings**: Choose between OpenAI, Google, or ZhipuAI embeddings
- **Local Storage**: All data stored locally - no cloud dependencies
- **Conversation History**: Maintains context across multiple questions

Expand All @@ -30,6 +32,7 @@ OPENAI_API_KEY=your_openai_api_key # Required for embeddings and OpenAI m

# Optional API Keys
OPENROUTER_API_KEY=your_openrouter_api_key # Required only if using OpenRouter models
ZHIPUAI_API_KEY=your_zhipuai_api_key # Required only if using ZhipuAI (GLM) models

# AWS Bedrock Configuration
AWS_ACCESS_KEY_ID=your_aws_access_key_id # Required for AWS Bedrock models
Expand All @@ -43,16 +46,21 @@ OPENAI_BASE_URL=https://custom-api-endpoint.com/v1 # Optional, for custom OpenA
# Ollama host
OLLAMA_HOST=https://your_ollama_host" # Optional: Add Ollama host if not local. default: http://localhost:11434

# ZhipuAI Configuration
ZHIPUAI_VERIFY_SSL=false # Optional: Disable SSL verification for proxy/VPN environments. default: true
DEEPWIKI_EMBEDDER_TYPE=zhipuai # Optional: Use ZhipuAI embeddings for RAG. default: openai

# Server Configuration
PORT=8001 # Optional, defaults to 8001
```

If you're not using Ollama mode, you need to configure an OpenAI API key for embeddings. Other API keys are only required when configuring and using models from the corresponding providers.
If you're not using Ollama mode, you need to configure an API key for embeddings (OpenAI by default, or set `DEEPWIKI_EMBEDDER_TYPE=zhipuai` to use ZhipuAI embeddings). Other API keys are only required when configuring and using models from the corresponding providers.

> 💡 **Where to get these keys:**
> - Get a Google API key from [Google AI Studio](https://makersuite.google.com/app/apikey)
> - Get an OpenAI API key from [OpenAI Platform](https://platform.openai.com/api-keys)
> - Get an OpenRouter API key from [OpenRouter](https://openrouter.ai/keys)
> - Get a ZhipuAI API key from [ZhipuAI Platform](https://open.bigmodel.cn/)
> - Get AWS credentials from [AWS IAM Console](https://console.aws.amazon.com/iam/)

#### Advanced Environment Configuration
Expand All @@ -63,6 +71,11 @@ DeepWiki supports multiple LLM providers. The environment variables above are re
- **Google Gemini**: Requires `GOOGLE_API_KEY`
- **OpenAI**: Requires `OPENAI_API_KEY`
- **OpenRouter**: Requires `OPENROUTER_API_KEY`
- **ZhipuAI (GLM)**: Requires `ZHIPUAI_API_KEY`
- Supports GLM-4 series models: glm-4-flash, glm-4-plus, glm-4, glm-4-air
- Includes embedding-3 for RAG functionality
- Optional: Set `DEEPWIKI_EMBEDDER_TYPE=zhipuai` to use ZhipuAI embeddings
- Optional: Set `ZHIPUAI_VERIFY_SSL=false` for proxy/VPN environments
- **AWS Bedrock**: Requires `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
- **Ollama**: No API key required (runs locally)

Expand All @@ -83,7 +96,7 @@ DeepWiki now uses JSON configuration files to manage various system components i

1. **`generator.json`**: Configuration for text generation models
- Located in `api/config/` by default
- Defines available model providers (Google, OpenAI, OpenRouter, AWS Bedrock, Ollama)
- Defines available model providers (Google, OpenAI, OpenRouter, ZhipuAI, AWS Bedrock, Ollama)
- Specifies default and available models for each provider
- Contains model-specific parameters like temperature and top_p

Expand Down Expand Up @@ -121,7 +134,7 @@ The API will be available at `http://localhost:8001`
When you provide a GitHub repository URL, the API:
- Clones the repository locally (if not already cloned)
- Reads all files in the repository
- Creates embeddings for the files using OpenAI
- Creates embeddings for the files using your chosen embedder (OpenAI, Google, or ZhipuAI)
- Stores the embeddings in a local database

### 2. Smart Retrieval (RAG)
Expand Down
24 changes: 16 additions & 8 deletions api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from api.google_embedder_client import GoogleEmbedderClient
from api.azureai_client import AzureAIClient
from api.dashscope_client import DashscopeClient
from api.zhipuai_client import ZhipuAIClient
from adalflow import GoogleGenAIClient, OllamaClient

# Get API keys from environment variables
Expand Down Expand Up @@ -60,7 +61,8 @@
"OllamaClient": OllamaClient,
"BedrockClient": BedrockClient,
"AzureAIClient": AzureAIClient,
"DashscopeClient": DashscopeClient
"DashscopeClient": DashscopeClient,
"ZhipuAIClient": ZhipuAIClient
}

def replace_env_placeholders(config: Union[Dict[str, Any], List[Any], str, Any]) -> Union[Dict[str, Any], List[Any], str, Any]:
Expand Down Expand Up @@ -128,15 +130,16 @@ def load_generator_config():
if provider_config.get("client_class") in CLIENT_CLASSES:
provider_config["model_client"] = CLIENT_CLASSES[provider_config["client_class"]]
# Fall back to default mapping based on provider_id
elif provider_id in ["google", "openai", "openrouter", "ollama", "bedrock", "azure", "dashscope"]:
elif provider_id in ["google", "openai", "openrouter", "ollama", "bedrock", "azure", "dashscope", "zhipuai"]:
default_map = {
"google": GoogleGenAIClient,
"openai": OpenAIClient,
"openrouter": OpenRouterClient,
"ollama": OllamaClient,
"bedrock": BedrockClient,
"azure": AzureAIClient,
"dashscope": DashscopeClient
"dashscope": DashscopeClient,
"zhipuai": ZhipuAIClient
}
provider_config["model_client"] = default_map[provider_id]
else:
Expand All @@ -149,7 +152,7 @@ def load_embedder_config():
embedder_config = load_json_config("embedder.json")

# Process client classes
for key in ["embedder", "embedder_ollama", "embedder_google"]:
for key in ["embedder", "embedder_ollama", "embedder_google", "embedder_zhipuai"]:
if key in embedder_config and "client_class" in embedder_config[key]:
class_name = embedder_config[key]["client_class"]
if class_name in CLIENT_CLASSES:
Expand All @@ -165,7 +168,9 @@ def get_embedder_config():
dict: The embedder configuration with model_client resolved
"""
embedder_type = EMBEDDER_TYPE
if embedder_type == 'google' and 'embedder_google' in configs:
if embedder_type == 'zhipuai' and 'embedder_zhipuai' in configs:
return configs.get("embedder_zhipuai", {})
elif embedder_type == 'google' and 'embedder_google' in configs:
return configs.get("embedder_google", {})
elif embedder_type == 'ollama' and 'embedder_ollama' in configs:
return configs.get("embedder_ollama", {})
Expand Down Expand Up @@ -217,9 +222,12 @@ def get_embedder_type():
Get the current embedder type based on configuration.

Returns:
str: 'ollama', 'google', or 'openai' (default)
str: 'zhipuai', 'ollama', 'google', or 'openai' (default)
"""
if is_ollama_embedder():
# Check EMBEDDER_TYPE environment variable first
if EMBEDDER_TYPE == 'zhipuai':
return 'zhipuai'
elif is_ollama_embedder():
return 'ollama'
elif is_google_embedder():
return 'google'
Expand Down Expand Up @@ -316,7 +324,7 @@ def load_lang_config():

# Update embedder configuration
if embedder_config:
for key in ["embedder", "embedder_ollama", "embedder_google", "retriever", "text_splitter"]:
for key in ["embedder", "embedder_ollama", "embedder_google", "embedder_zhipuai", "retriever", "text_splitter"]:
if key in embedder_config:
configs[key] = embedder_config[key]

Expand Down
7 changes: 7 additions & 0 deletions api/config/embedder.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
"task_type": "SEMANTIC_SIMILARITY"
}
},
"embedder_zhipuai": {
"client_class": "ZhipuAIClient",
"batch_size": 50,
"model_kwargs": {
"model": "embedding-3"
}
},
"retriever": {
"top_k": 20
},
Expand Down
19 changes: 19 additions & 0 deletions api/config/generator.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,25 @@
"top_p": 0.8
}
}
},
"zhipuai": {
"client_class": "ZhipuAIClient",
"default_model": "glm-4-flash",
"supportsCustomModel": true,
"models": {
"glm-4-flash": {
"temperature": 0.7
},
"glm-4-plus": {
"temperature": 0.7
},
"glm-4": {
"temperature": 0.7
},
"glm-4-air": {
"temperature": 0.7
}
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ def patched_watch(*args, **kwargs):
if os.path.isdir(item_path) and item != "logs":
api_subdirs.append(item_path)

# Also add Python files in the api root directory
api_subdirs.append(current_dir + "/*.py")
# Also watch the api root directory itself (for .py files)
api_subdirs.append(current_dir)

return original_watch(*api_subdirs, **kwargs)
watchfiles.watch = patched_watch
Expand Down
59 changes: 53 additions & 6 deletions api/simple_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from api.openrouter_client import OpenRouterClient
from api.bedrock_client import BedrockClient
from api.azureai_client import AzureAIClient
from api.zhipuai_client import ZhipuAIClient
from api.rag import RAG
from api.prompts import (
DEEP_RESEARCH_FIRST_ITERATION_PROMPT,
Expand Down Expand Up @@ -63,7 +64,7 @@ class ChatCompletionRequest(BaseModel):
type: Optional[str] = Field("github", description="Type of repository (e.g., 'github', 'gitlab', 'bitbucket')")

# model parameters
provider: str = Field("google", description="Model provider (google, openai, openrouter, ollama, bedrock, azure)")
provider: str = Field("google", description="Model provider (google, openai, openrouter, ollama, bedrock, azure, dashscope, zhipuai)")
model: Optional[str] = Field(None, description="Model name for the specified provider")

language: Optional[str] = Field("en", description="Language for content generation (e.g., 'en', 'ja', 'zh', 'es', 'kr', 'vi')")
Expand Down Expand Up @@ -427,20 +428,49 @@ async def chat_completions_stream(request: ChatCompletionRequest):
"top_p": model_config["top_p"]
}

api_kwargs = model.convert_inputs_to_api_kwargs(
input=prompt,
model_kwargs=model_kwargs,
model_type=ModelType.LLM
)
elif request.provider == "zhipuai":
logger.info(f"Using ZhipuAI with model: {request.model}")

# Check if an API key is set for ZhipuAI
if not os.getenv("ZHIPUAI_API_KEY"):
logger.warning("ZHIPUAI_API_KEY not configured, but continuing with request")

# Initialize ZhipuAI client (OpenAI-compatible)
model = ZhipuAIClient()
model_kwargs = {
"model": request.model,
"stream": True,
"temperature": model_config["temperature"]
}
# Only add top_p if it exists in the model config
if "top_p" in model_config:
model_kwargs["top_p"] = model_config["top_p"]

api_kwargs = model.convert_inputs_to_api_kwargs(
input=prompt,
model_kwargs=model_kwargs,
model_type=ModelType.LLM
)
else:
# Initialize Google Generative AI model
generation_config = {
"temperature": model_config["temperature"],
}
# Add top_p if present
if "top_p" in model_config:
generation_config["top_p"] = model_config["top_p"]
# Add top_k only if present (Google supports it)
if "top_k" in model_config:
generation_config["top_k"] = model_config["top_k"]

model = genai.GenerativeModel(
model_name=model_config["model"],
generation_config={
"temperature": model_config["temperature"],
"top_p": model_config["top_p"],
"top_k": model_config["top_k"]
}
generation_config=generation_config
)

# Create a streaming response
Expand Down Expand Up @@ -514,6 +544,23 @@ async def response_stream():
except Exception as e_azure:
logger.error(f"Error with Azure AI API: {str(e_azure)}")
yield f"\nError with Azure AI API: {str(e_azure)}\n\nPlease check that you have set the AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT, and AZURE_OPENAI_VERSION environment variables with valid values."
elif request.provider == "zhipuai":
try:
# Get the response and handle it properly using the previously created api_kwargs
logger.info("Making ZhipuAI API call")
response = await model.acall(api_kwargs=api_kwargs, model_type=ModelType.LLM)
# Handle streaming response from ZhipuAI (OpenAI-compatible format)
async for chunk in response:
choices = getattr(chunk, "choices", [])
if len(choices) > 0:
delta = getattr(choices[0], "delta", None)
if delta is not None:
text = getattr(delta, "content", None)
if text is not None:
yield text
except Exception as e_zhipuai:
logger.error(f"Error with ZhipuAI API: {str(e_zhipuai)}")
yield f"\nError with ZhipuAI API: {str(e_zhipuai)}\n\nPlease check that you have set the ZHIPUAI_API_KEY environment variable with a valid API key."
else:
# Generate streaming response
response = model.generate_content(prompt, stream=True)
Expand Down
10 changes: 7 additions & 3 deletions api/tools/embedder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ def get_embedder(is_local_ollama: bool = False, use_google_embedder: bool = Fals
Args:
is_local_ollama: Legacy parameter for Ollama embedder
use_google_embedder: Legacy parameter for Google embedder
embedder_type: Direct specification of embedder type ('ollama', 'google', 'openai')
embedder_type: Direct specification of embedder type ('zhipuai', 'ollama', 'google', 'openai')

Returns:
adal.Embedder: Configured embedder instance
"""
# Determine which embedder config to use
if embedder_type:
if embedder_type == 'ollama':
if embedder_type == 'zhipuai':
embedder_config = configs["embedder_zhipuai"]
elif embedder_type == 'ollama':
embedder_config = configs["embedder_ollama"]
elif embedder_type == 'google':
embedder_config = configs["embedder_google"]
Expand All @@ -29,7 +31,9 @@ def get_embedder(is_local_ollama: bool = False, use_google_embedder: bool = Fals
else:
# Auto-detect based on current configuration
current_type = get_embedder_type()
if current_type == 'ollama':
if current_type == 'zhipuai':
embedder_config = configs["embedder_zhipuai"]
elif current_type == 'ollama':
embedder_config = configs["embedder_ollama"]
elif current_type == 'google':
embedder_config = configs["embedder_google"]
Expand Down
Loading