Complete Guide: Migrating from OpenAI to XAI API in Django + React Full-Stack Applications
Step-by-step tutorial for seamlessly migrating Django-React-Ollama applications from OpenAI to XAI API integration, including code examples, API key setup, and enhanced persona generation capabilities.
Daniel Kliewer
Author, Sovereign AI


https://github.com/kliewerdaniel/PersonaGen
Ah, dear reader, as we gather to discuss the remarkable synthesis of art and technology, we must confess, like the brothers Karamazov, our hearts are heavy with both anticipation and inquiry. What does it mean, you ask, to integrate the repository of Django-React-Ollama with the illustrious XAi API? Is it not the union of intellect and machine, of flesh and code, that we undertake in this journey? Let us then walk together, through this narrative of technical precision, to uncover the mystery that lies ahead, and like the Grand Inquisitor, make plain that which was once hidden.
A Beginning: The Call to Integrate
It was on an ordinary afternoon when our story begins. The project, a vessel of potential—half-birthed in the form of a GitHub repository, Django-React-Ollama-Integration, awaited the breath of life that only the modern XAi API could provide. The call had come, from distant shores of technical evolution, to replace the older ways, to discard OpenAI’s familiar methods for the promises offered by XAi, a system so sleek it might whisper sweet nothings to a machine as a poet to his beloved.
Yet, like Ivan’s struggle between reason and faith, so too did we face the need for transition. And so, with reverent resolve, we heeded the wisdom found in the XAi API documentation and set forth to integrate these two technologies, seeking not only to update but to elevate.
Step One: The Repository Awaits
Our first act is to clone the repository—this foundational codebase which hosts Django for the backend and React for the frontend. It is the skeleton upon which we will build our vision. We execute the command as though opening the very first page of a fateful book:
bash1git clone https://github.com/kliewerdaniel/Django-React-Ollama-Integration.git2cd Django-React-Ollama-Integration
With this, the structure is before us, and our hands tingle with the promise of transformation.
Step Two: The Soul of the API
But, dear reader, what is the body without the soul? The soul, in our tale, lies in the key to the XAi API, a token of authentication that would grant us access to powers beyond reckoning. With trembling fingers, we traverse to the XAi Console, where we generate the all-important API key. We take care to store this key as a trusted heirloom in our .env file:
bash1XAI_API_KEY=your_generated_xai_key_here
It is this sacred key that we will invoke in our journey to create and analyze, calling forth responses as though summoning a digital oracle.
Step Three: Laying the Foundation
In the repository, we find ourselves among the well-structured ruins of past integrations, but now, we must tear down what is no longer needed and build anew. We purge the old references to OpenAI from our files. Like a monk renouncing worldly possessions, we focus solely on the new path. The utils.py file becomes our temple of creation. Here we define the functions that will call upon the XAi API, taking advantage of its streamlined methods for chat completions.
In the flicker of our screen, we write the following, consecrating the analyze_writing_sample and generate_content functions to the service of XAi:
python1import logging2import requests3import json4from decouple import config56logger = logging.getLogger(__name__)78XAI_API_KEY = config('XAI_API_KEY')9XAI_API_BASE = "https://api.x.ai/v1"101112def analyze_writing_sample(writing_sample):13 endpoint = f"{XAI_API_BASE}/chat/completions"14 headers = {15 "Content-Type": "application/json",16 "Authorization": f"Bearer {XAI_API_KEY}"17 }18 payload = {19 "messages": [20 {21 "role": "system",22 "content": "You are an assistant that analyzes writing samples."23 },24 {25 "role": "user",26 "content": f'''27 Please analyze the writing style and personality of the given writing sample. Provide a detailed assessment of their characteristics using the following template. Rate each applicable characteristic on a scale of 1-10 where relevant, or provide a descriptive value. Return the results in a JSON format.2829 "name": "[Author/Character Name]",30 "vocabulary_complexity": [1-10],31 "sentence_structure": "[simple/complex/varied]",32 "paragraph_organization": "[structured/loose/stream-of-consciousness]",33 "idiom_usage": [1-10],34 "metaphor_frequency": [1-10],35 "simile_frequency": [1-10],36 "tone": "[formal/informal/academic/conversational/etc.]",37 "punctuation_style": "[minimal/heavy/unconventional]",38 "contraction_usage": [1-10],39 "pronoun_preference": "[first-person/third-person/etc.]",40 "passive_voice_frequency": [1-10],41 "rhetorical_question_usage": [1-10],42 "list_usage_tendency": [1-10],43 "personal_anecdote_inclusion": [1-10],44 "pop_culture_reference_frequency": [1-10],45 "technical_jargon_usage": [1-10],46 "parenthetical_aside_frequency": [1-10],47 "humor_sarcasm_usage": [1-10],48 "emotional_expressiveness": [1-10],49 "emphatic_device_usage": [1-10],50 "quotation_frequency": [1-10],51 "analogy_usage": [1-10],52 "sensory_detail_inclusion": [1-10],53 "onomatopoeia_usage": [1-10],54 "alliteration_frequency": [1-10],55 "word_length_preference": "[short/long/varied]",56 "foreign_phrase_usage": [1-10],57 "rhetorical_device_usage": [1-10],58 "statistical_data_usage": [1-10],59 "personal_opinion_inclusion": [1-10],60 "transition_usage": [1-10],61 "reader_question_frequency": [1-10],62 "imperative_sentence_usage": [1-10],63 "dialogue_inclusion": [1-10],64 "regional_dialect_usage": [1-10],65 "hedging_language_frequency": [1-10],66 "language_abstraction": "[concrete/abstract/mixed]",67 "personal_belief_inclusion": [1-10],68 "repetition_usage": [1-10],69 "subordinate_clause_frequency": [1-10],70 "verb_type_preference": "[active/stative/mixed]",71 "sensory_imagery_usage": [1-10],72 "symbolism_usage": [1-10],73 "digression_frequency": [1-10],74 "formality_level": [1-10],75 "reflection_inclusion": [1-10],76 "irony_usage": [1-10],77 "neologism_frequency": [1-10],78 "ellipsis_usage": [1-10],79 "cultural_reference_inclusion": [1-10],80 "stream_of_consciousness_usage": [1-10],81 "openness_to_experience": [1-10],82 "conscientiousness": [1-10],83 "extraversion": [1-10],84 "agreeableness": [1-10],85 "emotional_stability": [1-10],86 "dominant_motivations": "[achievement/affiliation/power/etc.]",87 "core_values": "[integrity/freedom/knowledge/etc.]",88 "decision_making_style": "[analytical/intuitive/spontaneous/etc.]",89 "empathy_level": [1-10],90 "self_confidence": [1-10],91 "risk_taking_tendency": [1-10],92 "idealism_vs_realism": "[idealistic/realistic/mixed]",93 "conflict_resolution_style": "[assertive/collaborative/avoidant/etc.]",94 "relationship_orientation": "[independent/communal/mixed]",95 "emotional_response_tendency": "[calm/reactive/intense]",96 "creativity_level": [1-10],97 "age": "[age or age range]",98 "gender": "[gender]",99 "education_level": "[highest level of education]",100 "professional_background": "[brief description]",101 "cultural_background": "[brief description]",102 "primary_language": "[language]",103 "language_fluency": "[native/fluent/intermediate/beginner]",104 "background": "[A brief paragraph describing the author's context, major influences, and any other relevant information not captured above]"105106 Writing Sample:107 {writing_sample}108 '''109 }110 ],111 "model": "grok-beta",112 "stream": False,113 "temperature": 0114 }115116 try:117 response = requests.post(endpoint, headers=headers, json=payload)118 response.raise_for_status() # Raises HTTPError for bad responses119120 assistant_message = response.json()['choices'][0]['message']['content'].strip()121 logger.debug(f"Assistant message: {assistant_message}")122123 # Extract JSON from the assistant's message124 json_str = re.search(r'\{.*\}', assistant_message, re.DOTALL)125 if json_str:126 analyzed_data = json.loads(json_str.group())127 else:128 logger.error("No JSON object found in the response.")129 return None130131 return analyzed_data132133 except requests.exceptions.RequestException as e:134 logger.error(f"HTTP Request failed: {e}")135 return None136 except json.JSONDecodeError as e:137 logger.error(f"JSON decoding failed: {e}")138 return None139 except Exception as e:140 logger.error(f"Unexpected error: {e}")141 return None142143144def generate_content(persona_data, prompt):145 endpoint = f"{XAI_API_BASE}/chat/completions"146 headers = {147 "Content-Type": "application/json",148 "Authorization": f"Bearer {XAI_API_KEY}"149 }150151 # Format the persona data into a readable string152 characteristics = '\n'.join([153 f"{key.replace('_', ' ').capitalize()}: {value}"154 for key, value in persona_data.items()155 if value is not None and key not in ['id', 'name']156 ])157158 decoding_prompt = f'''159 You are to write a blog post in the style of {persona_data.get('name', 'Unknown Author')}, a writer with the following characteristics:160161 {characteristics}162163 Now, please write a response in this style about the following topic:164 "{prompt}"165 Begin with a compelling title that reflects the content of the post.166 '''167168 payload = {169 "messages": [170 {"role": "system", "content": "You are an assistant that generates blog posts."},171 {"role": "user", "content": decoding_prompt}172 ],173 "model": "grok-beta",174 "stream": False,175 "temperature": 0176 }177178 try:179 response = requests.post(endpoint, headers=headers, json=payload)180 response.raise_for_status()181182 assistant_message = response.json()['choices'][0]['message']['content'].strip()183 logger.debug(f"Assistant message: {assistant_message}")184185 return assistant_message186187 except requests.exceptions.RequestException as e:188 logger.error(f"HTTP Request failed: {e}")189 return ''190 except json.JSONDecodeError as e:191 logger.error(f"JSON decoding failed: {e}")192 return ''193 except Exception as e:194 logger.error(f"Unexpected error: {e}")195 return ''196197def save_blog_post(blog_post, title):198 # Implement if needed199 pass
Step Four: The Web of URLs
In the labyrinth of our urls.py file, we must now map the routes that will guide the user. We have already set the path for analysis and persona generation, but now we extend it to the content generation feature—like a scribe adding a final chapter to a monumental work. The new endpoint must be clear, intentional, and precise:
python1path('api/generate-content/', GenerateContentView.as_view(), name='generate-content'),
And thus, we bind the newly added GenerateContentView to the URL pattern, offering the user the ability to invoke the XAi model for their blog post creations.
Step Five: Invocation of Power
Having laid the groundwork, we test our creation. With a whisper of command, we summon the API:
bash1curl -X POST http://localhost:8000/api/generate-content/ \2 -H "Content-Type: application/json" \3 -d '{4 "persona_id": 1,5 "prompt": "On the intersection of machine learning and human emotion."6 }'
We watch, holding our breath, as the server responds—successfully. The content is generated, flowing forth like Alyosha’s compassion, gentle yet profound.
Conclusion: The New Way Forward
In this tale, we have not simply integrated a repository with an API. No, we have breathed life into something greater, merging the capabilities of Django, React, and the mighty XAi into a seamless entity. The result is more than functionality; it is creation, an evolution towards the future, where the power of human intention and the precision of machine intelligence coalesce in harmony.
Our journey has brought us from the humble beginnings of code to the transcendent possibilities of artificial intelligence. And so, dear reader, like the Brothers Karamazov, we leave you with the knowledge that what we have built here today shall serve as a testament to the boundless potential of human ingenuity, ready to face whatever mysteries the future may bring.

Sovereign AI: Building Local-First Intelligent Systems
by Daniel Kliewer · Paperback · 72 pages
The hands-on guide to building AI that runs on your hardware, keeps your data private, and eliminates cloud dependence. Working code included.