Skip to content

React集成示例

本页面展示了如何在 React 应用中集成和使用 XAI-SDK,包括基础集成、Hooks 使用、组件开发和最佳实践。

📋 示例列表

基础 React 应用

简单的 React AI 聊天应用

代码编辑器组件

带 AI 辅助功能的 React 代码编辑器

项目分析器

React 项目代码分析工具

自定义 Hooks

可复用的 XAI-SDK React Hooks

🚀 快速开始

安装依赖

bash
npm install xai-sdk @xai-sdk/react-adapter react react-dom
# 或者
yarn add xai-sdk @xai-sdk/react-adapter react react-dom

项目结构

src/
├── components/
│   ├── ChatInterface.tsx
│   ├── CodeEditor.tsx
│   └── AIAssistant.tsx
├── hooks/
│   ├── useXAI.ts
│   ├── useChat.ts
│   └── useCodeAnalysis.ts
├── contexts/
│   └── XAIContext.tsx
├── utils/
│   └── xai-config.ts
└── App.tsx

📚 基础示例

XAI Context Provider

首先创建一个 Context 来管理 XAI-SDK 实例:

tsx
// src/contexts/XAIContext.tsx
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { XAI_SDK } from 'xai-sdk';
import { ReactAdapterPlugin } from '@xai-sdk/react-adapter';
import { OpenAIProviderPlugin } from '@xai-sdk/openai-provider';

interface XAIContextType {
  sdk: XAI_SDK | null;
  isInitialized: boolean;
  error: string | null;
}

const XAIContext = createContext<XAIContextType>({
  sdk: null,
  isInitialized: false,
  error: null
});

interface XAIProviderProps {
  children: ReactNode;
  apiKey: string;
}

export const XAIProvider: React.FC<XAIProviderProps> = ({ children, apiKey }) => {
  const [sdk, setSdk] = useState<XAI_SDK | null>(null);
  const [isInitialized, setIsInitialized] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const initializeSDK = async () => {
      try {
        const sdkInstance = new XAI_SDK({ environment: 'browser' });
        
        // 注册插件
        await sdkInstance.registerPlugin(new ReactAdapterPlugin());
        await sdkInstance.registerPlugin(new OpenAIProviderPlugin({
          apiKey: apiKey
        }));
        
        await sdkInstance.initialize();
        
        setSdk(sdkInstance);
        setIsInitialized(true);
      } catch (err) {
        setError(err instanceof Error ? err.message : '初始化失败');
      }
    };

    if (apiKey) {
      initializeSDK();
    }
  }, [apiKey]);

  return (
    <XAIContext.Provider value={{ sdk, isInitialized, error }}>
      {children}
    </XAIContext.Provider>
  );
};

export const useXAI = () => {
  const context = useContext(XAIContext);
  if (!context) {
    throw new Error('useXAI must be used within an XAIProvider');
  }
  return context;
};

基础聊天组件

tsx
// src/components/ChatInterface.tsx
import React, { useState, useRef, useEffect } from 'react';
import { useXAI } from '../contexts/XAIContext';

interface Message {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  timestamp: Date;
}

const ChatInterface: React.FC = () => {
  const { sdk, isInitialized, error } = useXAI();
  const [messages, setMessages] = useState<Message[]>([]);
  const [input, setInput] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const messagesEndRef = useRef<HTMLDivElement>(null);

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  };

  useEffect(() => {
    scrollToBottom();
  }, [messages]);

  useEffect(() => {
    if (isInitialized) {
      addMessage('system', 'AI 助手已就绪,请输入您的问题。');
    }
  }, [isInitialized]);

  const addMessage = (role: Message['role'], content: string): string => {
    const id = Date.now().toString();
    const message: Message = {
      id,
      role,
      content,
      timestamp: new Date()
    };
    setMessages(prev => [...prev, message]);
    return id;
  };

  const updateMessage = (id: string, content: string) => {
    setMessages(prev => prev.map(msg => 
      msg.id === id ? { ...msg, content } : msg
    ));
  };

  const sendMessage = async () => {
    if (!input.trim() || !sdk || isLoading) return;

    const userMessage = input.trim();
    setInput('');
    addMessage('user', userMessage);
    setIsLoading(true);

    const loadingId = addMessage('assistant', '正在思考...');

    try {
      const response = await sdk.chat(userMessage, {
        stream: false,
        maxTokens: 1000,
        temperature: 0.7
      });

      updateMessage(loadingId, response.content);
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : '处理请求时出现错误';
      updateMessage(loadingId, `抱歉,${errorMessage}`);
    } finally {
      setIsLoading(false);
    }
  };

  const handleKeyPress = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      sendMessage();
    }
  };

  if (error) {
    return (
      <div className="chat-error">
        <h3>初始化错误</h3>
        <p>{error}</p>
      </div>
    );
  }

  if (!isInitialized) {
    return (
      <div className="chat-loading">
        <div className="spinner"></div>
        <p>正在初始化 AI 助手...</p>
      </div>
    );
  }

  return (
    <div className="chat-interface">
      <div className="chat-header">
        <h2>AI 助手</h2>
        <div className="status-indicator online"></div>
      </div>
      
      <div className="chat-messages">
        {messages.map((message) => (
          <div key={message.id} className={`message ${message.role}`}>
            <div className="message-header">
              <span className="role">
                {message.role === 'user' ? '用户' : 
                 message.role === 'assistant' ? 'AI助手' : '系统'}
              </span>
              <span className="timestamp">
                {message.timestamp.toLocaleTimeString()}
              </span>
            </div>
            <div className="message-content">
              {message.content}
            </div>
          </div>
        ))}
        <div ref={messagesEndRef} />
      </div>
      
      <div className="chat-input">
        <textarea
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyPress={handleKeyPress}
          placeholder="输入您的问题... (Shift+Enter 换行)"
          disabled={isLoading}
          rows={3}
        />
        <button 
          onClick={sendMessage} 
          disabled={!input.trim() || isLoading}
          className="send-button"
        >
          {isLoading ? '发送中...' : '发送'}
        </button>
      </div>
    </div>
  );
};

export default ChatInterface;

样式文件

css
/* src/styles/ChatInterface.css */
.chat-interface {
  display: flex;
  flex-direction: column;
  height: 600px;
  border: 1px solid #e1e5e9;
  border-radius: 8px;
  overflow: hidden;
  background: white;
}

.chat-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  background: #f8f9fa;
  border-bottom: 1px solid #e1e5e9;
}

.chat-header h2 {
  margin: 0;
  font-size: 18px;
  color: #24292e;
}

.status-indicator {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #28a745;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.message {
  max-width: 80%;
  padding: 12px;
  border-radius: 8px;
  word-wrap: break-word;
}

.message.user {
  align-self: flex-end;
  background: #0366d6;
  color: white;
}

.message.assistant {
  align-self: flex-start;
  background: #f1f3f4;
  border: 1px solid #d0d7de;
}

.message.system {
  align-self: center;
  background: #fff3cd;
  border: 1px solid #ffeaa7;
  color: #856404;
  font-style: italic;
}

.message-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 4px;
  font-size: 12px;
  opacity: 0.7;
}

.message-content {
  line-height: 1.4;
  white-space: pre-wrap;
}

.chat-input {
  display: flex;
  padding: 16px;
  border-top: 1px solid #e1e5e9;
  background: #f8f9fa;
  gap: 12px;
}

.chat-input textarea {
  flex: 1;
  padding: 8px 12px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  resize: none;
  font-family: inherit;
  font-size: 14px;
}

.chat-input textarea:focus {
  outline: none;
  border-color: #0366d6;
  box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.1);
}

.send-button {
  padding: 8px 16px;
  background: #0366d6;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.2s;
}

.send-button:hover:not(:disabled) {
  background: #0256cc;
}

.send-button:disabled {
  background: #6c757d;
  cursor: not-allowed;
}

.chat-loading, .chat-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 400px;
  text-align: center;
}

.spinner {
  width: 32px;
  height: 32px;
  border: 3px solid #f3f3f3;
  border-top: 3px solid #0366d6;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 16px;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

🔧 高级示例

自定义 Hooks

tsx
// src/hooks/useChat.ts
import { useState, useCallback } from 'react';
import { useXAI } from '../contexts/XAIContext';

interface ChatMessage {
  id: string;
  role: 'user' | 'assistant';
  content: string;
  timestamp: Date;
}

interface UseChatOptions {
  maxTokens?: number;
  temperature?: number;
  onError?: (error: Error) => void;
}

export const useChat = (options: UseChatOptions = {}) => {
  const { sdk } = useXAI();
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [isLoading, setIsLoading] = useState(false);

  const sendMessage = useCallback(async (content: string) => {
    if (!sdk || !content.trim()) return;

    const userMessage: ChatMessage = {
      id: Date.now().toString(),
      role: 'user',
      content: content.trim(),
      timestamp: new Date()
    };

    setMessages(prev => [...prev, userMessage]);
    setIsLoading(true);

    try {
      const response = await sdk.chat(content, {
        maxTokens: options.maxTokens || 1000,
        temperature: options.temperature || 0.7,
        stream: false
      });

      const assistantMessage: ChatMessage = {
        id: (Date.now() + 1).toString(),
        role: 'assistant',
        content: response.content,
        timestamp: new Date()
      };

      setMessages(prev => [...prev, assistantMessage]);
    } catch (error) {
      const err = error instanceof Error ? error : new Error('Unknown error');
      options.onError?.(err);
    } finally {
      setIsLoading(false);
    }
  }, [sdk, options]);

  const clearMessages = useCallback(() => {
    setMessages([]);
  }, []);

  return {
    messages,
    isLoading,
    sendMessage,
    clearMessages
  };
};
tsx
// src/hooks/useCodeAnalysis.ts
import { useState, useCallback } from 'react';
import { useXAI } from '../contexts/XAIContext';

interface AnalysisResult {
  score: number;
  suggestions: string[];
  metrics: {
    lines: number;
    complexity: number;
    maintainability: number;
  };
  issues: Array<{
    type: 'error' | 'warning' | 'info';
    message: string;
    line?: number;
  }>;
}

export const useCodeAnalysis = () => {
  const { sdk } = useXAI();
  const [isAnalyzing, setIsAnalyzing] = useState(false);
  const [result, setResult] = useState<AnalysisResult | null>(null);
  const [error, setError] = useState<string | null>(null);

  const analyzeCode = useCallback(async (code: string, language: string = 'javascript') => {
    if (!sdk || !code.trim()) return;

    setIsAnalyzing(true);
    setError(null);

    try {
      const analysis = await sdk.analyze(code, {
        type: 'code-quality',
        language,
        includeMetrics: true,
        includeSuggestions: true
      });

      setResult(analysis as AnalysisResult);
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : '分析失败';
      setError(errorMessage);
    } finally {
      setIsAnalyzing(false);
    }
  }, [sdk]);

  const clearResult = useCallback(() => {
    setResult(null);
    setError(null);
  }, []);

  return {
    analyzeCode,
    isAnalyzing,
    result,
    error,
    clearResult
  };
};

代码编辑器组件

tsx
// src/components/CodeEditor.tsx
import React, { useState, useRef, useEffect } from 'react';
import { useCodeAnalysis } from '../hooks/useCodeAnalysis';

interface CodeEditorProps {
  initialCode?: string;
  language?: string;
  onChange?: (code: string) => void;
}

const CodeEditor: React.FC<CodeEditorProps> = ({ 
  initialCode = '', 
  language = 'javascript',
  onChange 
}) => {
  const [code, setCode] = useState(initialCode);
  const [showAnalysis, setShowAnalysis] = useState(false);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const { analyzeCode, isAnalyzing, result, error } = useCodeAnalysis();

  const handleCodeChange = (newCode: string) => {
    setCode(newCode);
    onChange?.(newCode);
  };

  const handleAnalyze = async () => {
    await analyzeCode(code, language);
    setShowAnalysis(true);
  };

  const insertTab = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === 'Tab') {
      e.preventDefault();
      const textarea = e.currentTarget;
      const start = textarea.selectionStart;
      const end = textarea.selectionEnd;
      const newCode = code.substring(0, start) + '  ' + code.substring(end);
      setCode(newCode);
      
      // 设置光标位置
      setTimeout(() => {
        textarea.selectionStart = textarea.selectionEnd = start + 2;
      }, 0);
    }
  };

  return (
    <div className="code-editor">
      <div className="editor-toolbar">
        <div className="toolbar-left">
          <span className="language-label">{language}</span>
          <span className="lines-count">{code.split('\n').length} 行</span>
        </div>
        <div className="toolbar-right">
          <button 
            onClick={handleAnalyze}
            disabled={!code.trim() || isAnalyzing}
            className="analyze-button"
          >
            {isAnalyzing ? '分析中...' : '🔍 分析代码'}
          </button>
          <button 
            onClick={() => setShowAnalysis(!showAnalysis)}
            className="toggle-analysis"
            disabled={!result}
          >
            {showAnalysis ? '隐藏分析' : '显示分析'}
          </button>
        </div>
      </div>
      
      <div className="editor-container">
        <div className="editor-main">
          <textarea
            ref={textareaRef}
            value={code}
            onChange={(e) => handleCodeChange(e.target.value)}
            onKeyDown={insertTab}
            className="code-textarea"
            placeholder="在这里输入代码..."
            spellCheck={false}
          />
        </div>
        
        {showAnalysis && (result || error) && (
          <div className="analysis-panel">
            <div className="analysis-header">
              <h3>分析结果</h3>
              <button 
                onClick={() => setShowAnalysis(false)}
                className="close-button"
              >
                ×
              </button>
            </div>
            
            {error ? (
              <div className="analysis-error">
                <p>分析失败: {error}</p>
              </div>
            ) : result ? (
              <div className="analysis-content">
                <div className="metrics">
                  <div className="metric">
                    <span className="metric-label">质量评分</span>
                    <span className={`metric-value score-${getScoreClass(result.score)}`}>
                      {result.score}/100
                    </span>
                  </div>
                  <div className="metric">
                    <span className="metric-label">代码行数</span>
                    <span className="metric-value">{result.metrics.lines}</span>
                  </div>
                  <div className="metric">
                    <span className="metric-label">复杂度</span>
                    <span className="metric-value">{result.metrics.complexity}</span>
                  </div>
                </div>
                
                {result.suggestions.length > 0 && (
                  <div className="suggestions">
                    <h4>改进建议</h4>
                    <ul>
                      {result.suggestions.map((suggestion, index) => (
                        <li key={index}>{suggestion}</li>
                      ))}
                    </ul>
                  </div>
                )}
                
                {result.issues.length > 0 && (
                  <div className="issues">
                    <h4>发现的问题</h4>
                    <ul>
                      {result.issues.map((issue, index) => (
                        <li key={index} className={`issue-${issue.type}`}>
                          <span className="issue-type">{issue.type.toUpperCase()}</span>
                          <span className="issue-message">{issue.message}</span>
                          {issue.line && <span className="issue-line">第 {issue.line} 行</span>}
                        </li>
                      ))}
                    </ul>
                  </div>
                )}
              </div>
            ) : null}
          </div>
        )}
      </div>
    </div>
  );
};

const getScoreClass = (score: number): string => {
  if (score >= 80) return 'good';
  if (score >= 60) return 'medium';
  return 'poor';
};

export default CodeEditor;

主应用组件

tsx
// src/App.tsx
import React, { useState } from 'react';
import { XAIProvider } from './contexts/XAIContext';
import ChatInterface from './components/ChatInterface';
import CodeEditor from './components/CodeEditor';
import './styles/App.css';

const App: React.FC = () => {
  const [apiKey, setApiKey] = useState(localStorage.getItem('openai-api-key') || '');
  const [activeTab, setActiveTab] = useState<'chat' | 'editor'>('chat');
  const [showSettings, setShowSettings] = useState(!apiKey);

  const handleApiKeySubmit = (key: string) => {
    setApiKey(key);
    localStorage.setItem('openai-api-key', key);
    setShowSettings(false);
  };

  if (showSettings) {
    return (
      <div className="app">
        <div className="settings-modal">
          <div className="settings-content">
            <h2>配置 API Key</h2>
            <p>请输入您的 OpenAI API Key 以开始使用:</p>
            <ApiKeyForm onSubmit={handleApiKeySubmit} />
          </div>
        </div>
      </div>
    );
  }

  return (
    <XAIProvider apiKey={apiKey}>
      <div className="app">
        <header className="app-header">
          <h1>XAI-SDK React 示例</h1>
          <nav className="app-nav">
            <button 
              className={activeTab === 'chat' ? 'active' : ''}
              onClick={() => setActiveTab('chat')}
            >
              💬 聊天助手
            </button>
            <button 
              className={activeTab === 'editor' ? 'active' : ''}
              onClick={() => setActiveTab('editor')}
            >
              📝 代码编辑器
            </button>
            <button 
              onClick={() => setShowSettings(true)}
              className="settings-button"
            >
              ⚙️ 设置
            </button>
          </nav>
        </header>
        
        <main className="app-main">
          {activeTab === 'chat' ? (
            <ChatInterface />
          ) : (
            <CodeEditor 
              initialCode="// 在这里编写代码\nfunction hello() {\n  console.log('Hello, World!');\n}"
              language="javascript"
            />
          )}
        </main>
      </div>
    </XAIProvider>
  );
};

interface ApiKeyFormProps {
  onSubmit: (key: string) => void;
}

const ApiKeyForm: React.FC<ApiKeyFormProps> = ({ onSubmit }) => {
  const [key, setKey] = useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (key.trim()) {
      onSubmit(key.trim());
    }
  };

  return (
    <form onSubmit={handleSubmit} className="api-key-form">
      <input
        type="password"
        value={key}
        onChange={(e) => setKey(e.target.value)}
        placeholder="sk-..."
        className="api-key-input"
        required
      />
      <button type="submit" className="submit-button">
        保存并开始
      </button>
    </form>
  );
};

export default App;

🎨 TypeScript 类型定义

typescript
// src/types/xai.ts
export interface ChatMessage {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  timestamp: Date;
}

export interface AnalysisResult {
  score: number;
  suggestions: string[];
  metrics: {
    lines: number;
    complexity: number;
    maintainability: number;
  };
  issues: Issue[];
}

export interface Issue {
  type: 'error' | 'warning' | 'info';
  message: string;
  line?: number;
  column?: number;
}

export interface ChatOptions {
  maxTokens?: number;
  temperature?: number;
  stream?: boolean;
}

export interface AnalysisOptions {
  type: 'code-quality' | 'security' | 'performance';
  language: string;
  includeMetrics?: boolean;
  includeSuggestions?: boolean;
}

🧪 测试示例

tsx
// src/__tests__/ChatInterface.test.tsx
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { XAIProvider } from '../contexts/XAIContext';
import ChatInterface from '../components/ChatInterface';

// Mock XAI SDK
jest.mock('xai-sdk', () => ({
  XAI_SDK: jest.fn().mockImplementation(() => ({
    registerPlugin: jest.fn(),
    initialize: jest.fn(),
    chat: jest.fn().mockResolvedValue({ content: 'Mock response' })
  }))
}));

const renderWithProvider = (component: React.ReactElement) => {
  return render(
    <XAIProvider apiKey="test-key">
      {component}
    </XAIProvider>
  );
};

describe('ChatInterface', () => {
  test('renders chat interface', async () => {
    renderWithProvider(<ChatInterface />);
    
    await waitFor(() => {
      expect(screen.getByText('AI 助手')).toBeInTheDocument();
    });
  });

  test('sends message when button clicked', async () => {
    renderWithProvider(<ChatInterface />);
    
    await waitFor(() => {
      expect(screen.getByText('AI 助手已就绪')).toBeInTheDocument();
    });

    const input = screen.getByPlaceholderText(/输入您的问题/);
    const sendButton = screen.getByText('发送');

    fireEvent.change(input, { target: { value: 'Hello' } });
    fireEvent.click(sendButton);

    await waitFor(() => {
      expect(screen.getByText('Hello')).toBeInTheDocument();
    });
  });
});

📖 最佳实践

1. 错误边界

tsx
// src/components/ErrorBoundary.tsx
import React, { Component, ErrorInfo, ReactNode } from 'react';

interface Props {
  children: ReactNode;
}

interface State {
  hasError: boolean;
  error?: Error;
}

class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error('XAI SDK Error:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-boundary">
          <h2>出现了错误</h2>
          <p>{this.state.error?.message}</p>
          <button onClick={() => this.setState({ hasError: false })}>
            重试
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

2. 性能优化

tsx
// 使用 React.memo 优化组件渲染
const ChatMessage = React.memo<{ message: ChatMessage }>(({ message }) => {
  return (
    <div className={`message ${message.role}`}>
      <div className="message-content">{message.content}</div>
    </div>
  );
});

// 使用 useMemo 缓存计算结果
const MessageList: React.FC<{ messages: ChatMessage[] }> = ({ messages }) => {
  const sortedMessages = useMemo(() => {
    return messages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
  }, [messages]);

  return (
    <div className="message-list">
      {sortedMessages.map(message => (
        <ChatMessage key={message.id} message={message} />
      ))}
    </div>
  );
};

3. 自定义 Hook 模式

tsx
// src/hooks/useLocalStorage.ts
import { useState, useEffect } from 'react';

export const useLocalStorage = <T>(key: string, initialValue: T) => {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(`Error reading localStorage key "${key}":`, error);
      return initialValue;
    }
  });

  const setValue = (value: T | ((val: T) => T)) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(`Error setting localStorage key "${key}":`, error);
    }
  };

  return [storedValue, setValue] as const;
};

🚀 部署配置

Vite 配置

typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  define: {
    'process.env': {}
  },
  build: {
    rollupOptions: {
      external: ['xai-sdk'],
      output: {
        globals: {
          'xai-sdk': 'XAI_SDK'
        }
      }
    }
  }
});

环境变量

bash
# .env.local
VITE_OPENAI_API_KEY=your-api-key-here
VITE_XAI_SDK_DEBUG=true

📝 相关资源


💡 提示: 这些示例展示了 XAI-SDK 在 React 应用中的完整集成方案。您可以根据项目需求选择合适的组件和模式。

Released under the MIT License.